PowerShell can store a value securely in a file:
PS > Read-Host 'Enter password' -AsSecureString | ConvertFrom-SecureString | Out-File ~\Desktop\SerializedSecurePassword.txt
How does one deserialize the value stored in the text into a System.Security.SecureString in a C# application?
string path = #"C:\\Users\\<user>\\Desktop\\SerializedSecurePassword.txt";
string contents = File.ReadAllText(path);
System.Security.SecureString SecurePassword = ?;
Related
i'm trying to decode a string and save it into a file following this method
C# code working successfully:
string val;
var path = #"decoded.txt";
Console.Write("Enter value:");
val = Console.ReadLine();
byte[] bytes1 = Convert.FromBase64String(val);
File.WriteAllBytes(path, bytes1);
but i dont get the same result using bash:
echo -n realm_result.json.public_key | base64 -di > temp_key_public
EDIT
the working bash mlethod:
printf '%s' {{ realm_result.json.public_key }} | base64 -d > temp_key_public
thank you #konrad-rudolph for pointing to the type of variable, it is an ansible task result containing a string.
I need to quickly rename particular excel sheet. The xlsx file itself has many of them (dates - I have to point out the newest by name change). The only thing I found is the ability to change the name of the first worksheet. Any hints guys? I'm a total layman when it comes to c#
$xlspath = "D:\New folder\Testing.xlsx"
$xldoc = new-object -comobject Excel.application
$workbook = $xldoc.Workbooks.Open($xlspath )
$worksheet = $workbook.worksheets.item(1)
$worksheet.name = "Result"
$worksheet.SaveAS = ($xlspath)
$worksheet.Close()
$xldoc.Quit()
Without knowing the date format you have used to name the worksheets, below code should do what you want:
$xlspath = "D:\Test\Testing.xlsx"
$xldoc = New-Object -ComObject Excel.Application
$xldoc.Visible = $false
$xldoc.DisplayAlerts = $false
$workbook = $xldoc.Workbooks.Open($xlspath )
# find the worksheet that is named for the latest date
$latestSheet = ($workbook.WorkSheets |
Sort-Object #{Expression = { (Get-Date $_.Name) }} |
Select-Object -Last 1).Name
# get the worksheet object by its name
$worksheet = $workbook.WorkSheets.Item($latestSheet)
# and rename it
$worksheet.Name = "Result"
# close and save
$workbook.Close($true) # $true means 'save the changes'
$xldoc.Quit()
# Important! release the COM objects from memory
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xldoc)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Before:
After:
As you can see my date format is Dutch (NL), so in the form of dd-MM-yyyy. Yours could be different, so you may need to change Get-Date $_.Name into [datetime]$_.Name
Edit
If you have more excel files like that in a folder, you can do this:
$xlspath = "D:\Test"
$xldoc = New-Object -ComObject Excel.Application
$xldoc.Visible = $false
$xldoc.DisplayAlerts = $false
# get the files and iterate over them
Get-ChildItem -Path $xlspath -Filter '*.xlsx' -File | ForEach-Object {
$workbook = $xldoc.Workbooks.Open($_.FullName )
# test if there isn't already a worksheet named 'Result' in that file
try {
$worksheet = $workbook.WorkSheets.Item("Result")
Write-Warning "File '$($_.FullName)' already has a sheet called 'Result'. Skipping file."
$workbook.Close($false)
continue # skip this file and proceed with the next
}
catch {}
# find the worksheet that is named for the latest date
$latestSheet = ($workbook.WorkSheets |
Sort-Object #{Expression = { (Get-Date $_.Name) }} |
Select-Object -Last 1).Name
# get the worksheet object by its name
$worksheet = $workbook.WorkSheets.Item($latestSheet)
# and rename it
$worksheet.Name = "Result"
# close and save
$workbook.Close($true) # $true means 'save the changes'
}
$xldoc.Quit()
# Important! release the COM objects from memory
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xldoc)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
I'm creating an application that analyzes the entries in the Boot Configuration Data (BCD).
I've tried with PowerShell, but it seems that it doesn't provide any cmdlets to deal with it. So, I've fallen back to .NET, espically C#.
I would like to have something obtain the BCD entries like this
var entries = bcd.GetEntries();
with entries being an IList<BcdEntry>
class BcdEntry
{
public string Name {get; set; }
IDictionary<string, IList<string>> Properties { get; set; }
}
The problem is that I don't know how to obtain the entries. Invoking BCDEdit is a possibility, but it requires to parse the output of the command, that is a tedious task.
I hope you can think of a solution for my problem.
A PSv4+ solution that parses bcdedit.exe /enum output into a list of custom objects:
# IMPORTANT: bcdedit /enum requires an ELEVATED session.
$bcdOutput = (bcdedit /enum) -join "`n" # collect bcdedit's output as a *single* string
# Initialize the output list.
$entries = New-Object System.Collections.Generic.List[pscustomobject]]
# Parse bcdedit's output.
($bcdOutput -split '(?m)^(.+\n-)-+\n' -ne '').ForEach({
if ($_.EndsWith("`n-")) { # entry header
$entries.Add([pscustomobject] #{ Name = ($_ -split '\n')[0]; Properties = [ordered] #{} })
} else { # block of property-value lines
($_ -split '\n' -ne '').ForEach({
$propAndVal = $_ -split '\s+', 2 # split line into property name and value
if ($propAndVal[0] -ne '') { # [start of] new property; initialize list of values
$currProp = $propAndVal[0]
$entries[-1].Properties[$currProp] = New-Object Collections.Generic.List[string]
}
$entries[-1].Properties[$currProp].Add($propAndVal[1]) # add the value
})
}
})
# Output a quick visualization of the resulting list via Format-Custom
$entries | Format-Custom
Note:
As LotPing observes,
bcdedit.exe output is partially localized; specifically, the following items:
entry headers (e.g., English Windows Boot Manager is Administrador de arranque de Windows in Spanish)
curiously, also the name of the property named identifier in English (e.g., Identificador in Spanish).
For the sake of brevity, the code makes no attempt to map localized names to their US-English counterparts, but it could be done.
Also, the sample bcdedit output posted with this ServerFault question (a duplicate) suggests that there may be property names that are so long that they run into their values, without intervening whitespace and without truncation.
If that is not just an artifact of posting, more work would be needed to handle this case; this article contains a list of property names.
[pscustomobject] instances are used rather than instances of a custom BcdEntry class; in PSv5+, you could create such a custom class directly in PowerShell.
The property values are all captured as string values, collected in a [List[string]] list (even if there's only 1 value); additional work would be required to interpret them as specific types;
e.g., [int] $entries[1].Properties['allowedinmemorysettings'][0] to convert string '0x15000075' to an integer.
Sample input / output:
Given bcdedit.exe /enum output such as this...
Windows Boot Manager
--------------------
identifier {bootmgr}
device partition=C:
displayorder {current}
{e37fc869-68b0-11e8-b4cf-806e6f6e6963}
description Windows Boot Manager
locale en-US
inherit {globalsettings}
default {current}
resumeobject {9f3d8468-592f-11e8-a07d-e91e7e2fad8b}
toolsdisplayorder {memdiag}
timeout 0
Windows Boot Loader
-------------------
identifier {current}
device partition=C:
path \WINDOWS\system32\winload.exe
description Windows 10
locale en-US
inherit {bootloadersettings}
recoverysequence {53f531de-590e-11e8-b758-8854872f7fe5}
displaymessageoverride Recovery
recoveryenabled Yes
allowedinmemorysettings 0x15000075
osdevice partition=C:
systemroot \WINDOWS
resumeobject {9f3d8468-592f-11e8-a07d-e91e7e2fad8b}
nx OptIn
bootmenupolicy Standard
... the above command yields this:
class PSCustomObject
{
Name = Windows Boot Manager
Properties =
[
class DictionaryEntry
{
Key = identifier
Value =
[
{bootmgr}
]
Name = identifier
}
class DictionaryEntry
{
Key = device
Value =
[
partition=C:
]
Name = device
}
class DictionaryEntry
{
Key = displayorder
Value =
[
{current}
{e37fc869-68b0-11e8-b4cf-806e6f6e6963}
]
Name = displayorder
}
class DictionaryEntry
{
Key = description
Value =
[
Windows Boot Manager
]
Name = description
}
...
]
}
class PSCustomObject
{
Name = Windows Boot Loader
Properties =
[
class DictionaryEntry
{
Key = identifier
Value =
[
{current}
]
Name = identifier
}
class DictionaryEntry
{
Key = device
Value =
[
partition=C:
]
Name = device
}
class DictionaryEntry
{
Key = path
Value =
[
\WINDOWS\system32\winload.exe
]
Name = path
}
class DictionaryEntry
{
Key = description
Value =
[
Windows 10
]
Name = description
}
...
]
}
To process the entries programmatically:
foreach($entry in $entries) {
# Get the name.
$name = $entry.Name
# Get a specific property's value.
$prop = 'device'
$val = $entry.Properties[$prop] # $val is a *list*; e.g., use $val[0] to get the 1st item
}
Note: $entries | ForEach-Object { <# work with entry $_ #> }, i.e. using the pipeline is an option too, but if the list of entries is already in memory, a foreach loop is faster.
I made some changes to #mklement0 script, too much to put in comments.
To solve the multiline properties problem these properties (which all
seem to be enclosed in curly braces) are joined with a RegEx replace.
to be locale independent the script uses just the dash line marking
the section header, to split contents (one caveat it inserts a blank
first entry)
I was wondering why there were only 4 Dictionary entries in the
output until I found the default value for $FormatEnumerationLimit
is 4
To avoid line breaks in output the script uses Out-String -Width 4096
## Q:\Test\2018\06\20\SO_50946956.ps1
# IMPORTANT: bcdedit /enu, requires an ELEVATED session.
#requires -RunAsAdministrator
## the following line imports the file posted by SupenJMN for testing
$bcdOutput = (gc ".\BCDEdit_ES.txt") -join "`n" -replace '\}\n\s+\{','},{'
## for a live "bcdedit /enum all" uncomment the following line
# $bcdOutput = (bcdedit /enum all) -join "`n" -replace '\}\n\s+\{','},{'
# Create the output list.
$entries = New-Object System.Collections.Generic.List[pscustomobject]]
# Parse bcdedit's output into entry blocks and construct a hashtable of
# property-value pairs for each.
($bcdOutput -split '(?m)^([a-z].+)\n-{10,100}\n').ForEach({
if ($_ -notmatch ' +') {
$entries.Add([pscustomobject] #{ Name = $_; Properties = [ordered] #{} })
} else {
($_ -split '\n' -ne '').ForEach({
$keyValue = $_ -split '\s+', 2
$entries[-1].Properties[$keyValue[0]] = $keyValue[1]
})
}
})
# Output a quick visualization of the resulting list via Format-Custom
$FormatEnumerationLimit = 20
$entries | Format-Custom | Out-String -Width 4096 | Set-Content BCDEdit_ES_Prop.txt
Shorted sample output of the script (~700 lines)
class PSCustomObject
{
Name =
Properties =
[
]
}
class PSCustomObject
{
Name = Administrador de arranque de firmware
Properties =
[
class DictionaryEntry
{
Key = Identificador
Value = {fwbootmgr}
Name = Identificador
}
class DictionaryEntry
{
Key = displayorder
Value = {bootmgr},{e37fc869-68b0-11e8-b4cf-806e6f6e6963},{05d4f193-712c-11e8-b4ea-806e6f6e6963},{05d4f194-712c-11e8-b4ea-806e6f6e6963},{cb6d5609-712f-11e8-b4eb-806e6f6e6963},{cb6d560a-712f-11e8-b4eb-806e6f6e6963},{cb6d560b-712f-11e8-b4eb-806e6f6e6963}
Name = displayorder
}
class DictionaryEntry
{
Key = timeout
Value = 1
Name = timeout
}
]
}
My approach would look somewhat like this:
(bcdedit /enum | Out-String) -split '(?<=\r\n)\r\n' | ForEach-Object {
$name, $data = $_ -split '\r\n---+\r\n'
$props = [ordered]#{
'name' = $name.Trim()
}
$data | Select-String '(?m)^(\S+)\s\s+(.*)' -AllMatches |
Select-Object -Expand Matches |
ForEach-Object { $props[$_.Groups[1].Value] = $_.Groups[2].Value.Trim() }
[PSCustomObject]$props
}
The above code basically starts with merging the bcdedit output into a single string like the other answers do, then splits that string into blocks of boot configuration data. Each of these blocks is then split again to separate the title from the actual data. The title is added to a hashtable as the name of the boot config section, then the data block is parsed with a regular expression for key/value pairs. These are appended to the hashtable, which is finally converted to a custom object.
Because of the the ordered and PSCustomObject type accelerators the code requires at least PowerShell v3.
Of course there are various optimizations you could apply to the basic example code above. For instance, different boot config sections might have different properties. The boot manager section has properties like toolsdisplayorder and timeout that are not present in the boot loader section, and the boot loader section has properties like osdevice and systemroot that are not present in the boot manager section. If you want a consistent set of properties for all generated objects you could pipe them through a Select-Object with a list of the properties you want your objects to have, e.g.:
... | Select-Object 'name', 'identifier', 'default', 'osdevice' 'systemroot'
Properties not present in the list will be dropped from the objects, while properties that are not present in an object will be added with an empty value.
Also, instead of creating all values as strings you could convert them to a more fitting type or just modify the value, e.g. to remove curly brackets from a string.
... | ForEach-Object {
$key = $_.Groups[1].Value
$val = $_.Groups[2].Value.Trim()
$val = $val -replace '^\{(.*)\}$', '$1'
if ($val -match '^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$') {
$val = [guid]$val
} elseif ($val -eq 'yes' -or $val -eq 'true') {
$val = $true
} elseif ($val -eq 'no' -or $val -eq 'false') {
$val = $false
} elseif ($key -eq 'locale') {
$val = [Globalization.CultureInfo]$val
}
$props[$key] = $val
}
I have the following PowerShell script being run on my build server
Write-Host "Current Path $env:Agent_BuildDirectory"
Write-Host "Build Number $env:Build_BuildNumber"
$squirrel = "$env:BUILD_SOURCESDIRECTORY\packages\squirrel.windows.*\tools\Squirrel.exe"
$releaseDir = '.\Releases'
$nugetPackFile = ".\MyApp\MyApp.$env:Build_BuildNumber.nupkg"
Write-Host $squirrel
Write-Host $nugetPackFile
if((Test-Path $nugetPackFile) -and (Test-Path $squirrel)) {
$squirrelArg1 = '--releasify=' + $nugetPackFile
$squirrelArg2 = '--releaseDir=' + $releaseDir
& $squirrel $squirrelArg1 $squirrelArg2
}
It runs and it creates only a nupkg in the .\Releases folder. If I run the same --releasify command in the Visual Studio instance on my build server agent it creates all the setup.exe and Releases file. Why is this PowerShell script not working the same way the command being run in the NuGet PowerShell window in VS is?
I've not played with Squirrel, so this may not work; but too much code here to just submit as a comment...
Try this:
Write-Host "Current Path $env:Agent_BuildDirectory"
Write-Host "Build Number $env:Build_BuildNumber"
$squirrel = Get-Item (Join-Path $env:BUILD_SOURCESDIRECTORY "packages\squirrel.windows.*\tools\Squirrel.exe") | select -First 1 -Expand FullName
$releaseDir = '.\Releases'
$nugetPackFile = ".\MyApp\MyApp.$env:Build_BuildNumber.nupkg"
Write-Host $squirrel
Write-Host $nugetPackFile
if((Test-Path $nugetPackFile) -and (Test-Path $squirrel)) {
$squirrelArg1 = "--releasify=`"$nugetPackFile`""
$squirrelArg2 = "--releaseDir=`"$releaseDir`""
& $squirrel $squirrelArg1 $squirrelArg2
}
Getting Squirrel.exe Path
(Join-Path $env:BUILD_SOURCESDIRECTORY "packages\squirrel.windows.*\tools\Squirrel.exe")
- here I use Join-Path to avoid any issues around whether or not the value of $env:BUILD_SOURCESDIRECTORY ends in a backslash.
Get-Item - I put this before that path so that it will resolve the path to a valid path (i.e. working out any matches of the asterisk/wildcard).
| select -First 1 -Expand FullName I then add this to get the first path which matches the result, and to return the full file path to squirrel.exe
Passing Parameters
For the statements below, I added double quotes around the paths; sometimes this is required to clarify which argument they relate to; particularly if there are any spaces or special characters in the paths. I also switched from using + to putting the variable within double quotes as this makes it simpler to concatenate the quotes within the string. I used backticks on the quotes in the string to escape those characters.
$squirrelArg1 = "--releasify=`"$nugetPackFile`""
$squirrelArg2 = "--releaseDir=`"$releaseDir`""
Hope that helps, but sadly this is very much guesswork by me; sorry.
Update
Getting the latest version; assuming asterisk in the path packages\squirrel.windows.*\tools\Squirrel.exe represents the version number in the form: Major.Minor.Build.
$squirrel = Get-Item (Join-Path $env:BUILD_SOURCESDIRECTORY "packages\squirrel.windows.*\tools\Squirrel.exe") | %{
if ($_ -match '.*\\squirrel\.windows\.(?<Major>\d+)\.(?<Minor>\d+)\.(?<Build>\d+)\\tools\\Squirrel\.exe') {
(new-object -TypeName PSObject -Property $matches)
}
} | sort #{e={$_.Major};a=0}, #{e={$_.Minor};a=0}, #{e={$_.Build};a=0} | select -First 1 -ExpandProperty '0'
I found the answer here
Write-Host "Current Path $env:Agent_BuildDirectory"
Write-Host "Build Number $env:Build_BuildNumber"
$squirrel = Get-Item (Join-Path $env:BUILD_SOURCESDIRECTORY "packages\squirrel.windows.*\tools\Squirrel.exe") | %{
if ($_ -match '.*\\squirrel\.windows\.(?<Major>\d+)\.(?<Minor>\d+)\.(?<Build>\d+)\\tools\\Squirrel\.exe') {
(new-object -TypeName PSObject -Property $matches)
}
} | sort #{e={$_.Major};a=0}, #{e={$_.Minor};a=0}, #{e={$_.Build};a=0} | select -First 1 -ExpandProperty '0'
Set-Alias Squirrel $squirrel
$releaseDir = '.\Releases'
$nugetPackFile = ".\MyApp\MyApp.$env:Build_BuildNumber.nupkg"
Write-Host $squirrel
Write-Host $nugetPackFile
if((Test-Path $nugetPackFile) -and (Test-Path $squirrel)) {
Squirrel --releasify $nugetPackFile --releaseDir $releaseDir | Write-Output
}
Much thanks goes to #JohnLBevan for helping to fix up my powershell code.
In some part of my code, I check if a file exists and then I open it.
One employee encountered a problem with filenames containing more than one space character.
I checked and it's true. Here's a snippet of my code:
string filePath = Path.Combine(helper.MillTestReportPath, fileName);
// Ouverture du fichier
if (File.Exists(filePath))
{
Process.Start(filePath);
}
else
{
MessageBox.Show("Le fichier n'existe pas!", "Fichier introuvable", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Everything works just find with almost every file but when a file ("SPAM CERTS S O 94318099 P O 10610.msg" for example) contains more than one space, I get false with File.Exists and even if I directly try to run Process.Start it fails...
Any idea about how I could fix that?
Thanks a lot!
According to MSDN documentation, File.Exists returns:
true if the caller has the required permissions and path contains the name of an existing file; otherwise, false. This method also returns false if path is null, an invalid path, or a zero-length string. If the caller does not have sufficient permissions to read the specified file, no exception is thrown and the method returns false regardless of the existence of path.
If the file exists, then probably the user that is trying to access the file does not have necessary permissions.
I suspect your filename(s) do not only contain ANSI space characters (char)32 0020hex but other ANSI characters that are indistinguishable from space characters.
If your files reside on an NTFS drive, file names can even contain Unicode characters.
MSDN: Character Sets Used in File Names
I wrote a small PowerShell script that shows you the filenames of the current folder in hex
dir | % {
$chars = $_.Name.ToCharArray(); """$($_.Name)""";
$result = "|";
foreach ($char in $chars) {
$result += [String]::Format(" {0} |",$char)
};
"$result";
$result = "|"
foreach ($char in $chars) {
$hexChar = [System.Convert]::ToInt32($char);
$result += $hexChar.ToString("x4");
$result += "|";
};
"$result`r`n";
}
Typical output is
"1000 €.txt"
| 1 | 0 | 0 | 0 | | € | . | t | x | t |
|0031|0030|0030|0030|0020|20ac|002e|0074|0078|0074|
"A normal file.txt"
| A | | n | o | r | m | a | l | | f | i | l | e | . | t | x | t |
|0041|0020|006e|006f|0072|006d|0061|006c|0020|0066|0069|006c|0065|002e|0074|0078|0074|
"what the ңёςк.txt"
| w | h | a | t | | t | h | e | | ң | ё | ς | к | . | t | x | t |
|0077|0068|0061|0074|0020|0074|0068|0065|0020|04a3|0451|03c2|043a|002e|0074|0078|0074|
etc.
You can see real ANSI spaces as 0020hex here.
The number of spaces should not be a problem. Did you check the output string of filePath? I'm sure it will not be right. As Henk suggested, if the output is not correct try to change to Path.Combine().
Bonne journée
Ran this test code using the same filename you've specified:
const string path = #"C:\TEMP\SPAM CERTS S O 94318099 P O 10610.msg";
if (File.Exists(path)) {
Trace.WriteLine("EXIST");
Process.Start(path);
}
else {
Trace.WriteLine("NOT EXIST");
}
The file is correctly found to exist even with multiple sequential spaces, etc. It also successfully launches the associated program (Noteapad++ in my case).
I suspect, as others indicate, that your problem is elsewhere. What is the failure you are seeing with Process.Start?
What happens when you try this with that file path:
try {
string path = Path.Combine(helper.MillTestReportPath, fileName);
using (FileStream fs = File.Open(path, FileMode.CreateNew)) {
}
} catch (IOException ex) {
// any exception here?
}
I think others have already covered the File related stuff I would check but have you considered localization/encoding in your check string vs the local file system?
It appears you are using ?German? in your message box prompt, might be comparing apples to oranges... just a thought.
Hey. Please list the parent dir programmatically. And then for each child file echo all the filenames char-by-char. Preferrably in hex or unicode codes.
You're probably having some non-trivial whitespace character somewhere in the file name. Especially if the filename was generated automatically from some keystore or xml file.