Using Switch Case to Replace If Condition - switch-statement

I would like to understand more about switch statement and how to implement it. I have the following raw code to set the paging file. I would like to change the if and elseif condition after "Write-Host Windows 2008 edition detected" to switch case.
Is it possible to do that with Switch statement? I have tried different formula on that, but still couldn't find the perfect code.
Here is the code.
$OSbuild = [environment]::OSVersion.Version.Build ## Checking the OS version
$Drives = ".\Drives.txt"
$Cdrive = "C: Hard Drive"
$Ddrive = "D: Hard Drive"
$Pdrive = "P: Hard Drive"
$OthDrive1 = "[^DP]: Hard Drive"
$OthDrive2 = "[^CDP]: Hard Drive"
$Disk = Get-WmiObject win32_logicaldisk
Foreach ($Drive in $Disk)
{
Switch ($Drive.DriveType)
{
1{$Disks = $Drive.DeviceID + " Unknown"; Break}
2{$Disks = $Drive.DeviceID + " Floppy or Removable Drive"; Break}
3{$Disks = $Drive.DeviceID + " Hard Drive"; Break}
4{$Disks = $Drive.DeviceID + " Network Drive"; Break}
5{$Disks = $Drive.DeviceID + " CD"; Break}
6{$Disks = $Drive.DeviceID + " RAM Disk"; Break}
}
Write $Disks >> $Drives
}
if (Get-Content $Drives | ? {$_ -like $Pdrive})
{
Proces A
}
elseif ($OSbuild -eq 6001 -or 7601)
{
Write-Host "Windows 2008 edition detected."
$OSversion = "2008"
if (Get-Content $Drives | ? {$_ -like $Ddrive}) ## Multiple drives found (with D) in the server
{
Process B
}
elseif (Get-Content $Drives | ? {$_ -match $OthDrive2}) ## Multiple drives found (without D) in the server
{
Process C
}
elseif (Get-Content $Drives | ? {$_ -like $Cdrive -notmatch $OthDrive1}) ## Only C drive found in the server
{
Process D
}
else
{
Write "Couldn't find the paging file rule for this server!"
}
}

Related

Better than Switch case in powershel?

I have an array like 5 system IDs for now like SID_1_name, SID_2_name......For each system ID .I need to add some details. So I have written powershell script of switch case .Which is working fine for now. But I wonder in future we may add more systems so that I need to add more cases which expands the script...Is there better way to do for future purpose aswell
$excel=#()
$list = Get-AznetworkInterface |where-Object {$_.ResourceGroupName -Clike '*$(givenVarible)'} |Select-Object
foreach ($i in $list) {
$x = " " | Select-Object SID1_name,SID1_VIP,SID2_name,SID2_VIP,SID3_name,SID3_VIP
$case =1
While ($case -1t $i.IpConfigurations.Count)
{
switch ($case){
1 {
$x.SID1_name = $i.IPconfigurations[$case];
$x.SID1_VIP = $i.IPconfigurations[$case].PrivateIpaddress;
break
}
2 {
$x.SID2_name = $i.IPconfigurations[$case];
$x.SID2_VIP = $i.IPconfigurations[$case].PrivateIpaddress;
break
}
3 {
$x.SID1_name = $i.IPconfigurations[$case];
$x.SID1_VIP = $i.IPconfigurations[$case].PrivateIpaddress;
break
}
$case =$case+1
$excel +=$x
$excel | Format-Table SID1_name,SID1_VIP,SID2_name,SID2_VIP,SID3_name,SID3_VIP
$excel |Export-Csv -NTI - Path "$(Build.ArtifactoryStagingDirectory)/report.csv"

Efficiently search a string in large files

How can I check if a string exists in:
1 text file;
size up until 10GB;
taking into account that the file is only one line;
the file only contains random numbers 1 to 9;
using powershell (because I think it will be more efficient, although I don't know how to program in this language);
I have tried this in batch:
FINDSTR "897516" decimal_output.txt
pause
But as I said I need the faster and more efficient way to do this.
I also tried this code that I have found in stackoverflow:
$SEL = Select-String -Path C:\Users\fabio\Desktop\CONVERTIDOS\dec_output.txt -Pattern "123456"
if ($SEL -ne $null)
{
echo Contains String
}
else
{
echo Not Contains String
}
But I get the error below, and I don't know if this code is the most solid or adequate. The error:
Select-String : Tipo de excepção 'System.OutOfMemoryException' accionado.
At C:\Users\fabio\Desktop\1.ps1:1 char:8
+ $SEL = Select-String -Path C:\Users\fabio\Desktop\CONVERTIDOS\dec_out ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Select-String], OutOfMemoryException
+ FullyQualifiedErrorId : System.OutOfMemoryException,Microsoft.PowerShell.Commands.SelectStringCommand
This should do the job:
#################################################################################################################
#
# Searches for a user defined string in the $input_file and counts matches. Works with files of any size.
#
# Adjust source directory and input file name.
#
$source = "C:\adjust\path"
$input_file = "file_name.extension"
#
#
# Define the string you want to search for. Keep quotation marks even if you only search for numbers (otherwise
# $pattern.Length will be 1 and this script will no longer work with files larger than the $split_size)!
#
$pattern = "Enter the string to search for in here"
#
#
# Using Get-Content on an input file with a size of 1GB or more will cause System.OutOfMemoryExceptions,
# therefore a large file gets temporarily split up.
#
$split_size = 100MB
#
#
# Thanks #Bob (https://superuser.com/a/1295082/868077)
#################################################################################################################
Set-Location $source
if (test-path ".\_split") {
while ($overwrite -ne "true" -and $overwrite -ne "false") {
"`n"
$overwrite = Read-Host ' Splitted files already/still exist! Delete and overwrite?'
if ($overwrite -match "y") {
$overwrite = "true"
Remove-Item .\_split -force -recurse
$a = "`n Deleted existing splitted files!"
} elseif ($overwrite -match "n") {
$overwrite = "false"
$a = "`n Continuing with existing splitted files!"
} elseif ($overwrite -match "c") {
exit
} else {
Write-Host "`n Error: Invalid input!`n Type 'y' for 'yes'. Type 'n' for 'no'. Type 'c' for 'cancel'. `n`n`n"
}
}
}
Clear-Host
if ((Get-Item $input_file).Length -gt $split_size) {
while ($delete -ne "true" -and $delete -ne "false") {
"`n"
$delete = Read-Host ' Delete splitted files afterwards?'
if ($delete -match "y") {
$delete = "true"
$b = "`n Splitted files will be deleted afterwards!"
} elseif ($delete -match "n") {
$delete = "false"
$b = "`n Splitted files will not be deleted afterwards!"
} elseif ($delete -match "c") {
exit
} else {
Write-Host "`n Error: Invalid input!`n Type 'y' for 'yes'. Type 'n' for 'no'. Type 'c' for 'cancel'. `n`n`n"
}
}
Clear-Host
$a
$b
Write-Host `n This may take some time!
if ($overwrite -ne "false") {
New-Item -ItemType directory -Path ".\_split" >$null 2>&1
[Environment]::CurrentDirectory = Get-Location
$bytes = New-Object byte[] 4096
$in_file = [System.IO.File]::OpenRead($input_file)
$file_count = 0
$finished = $false
while (!$finished) {
$file_count++
$bytes_to_read = $split_size
$out_file = New-Object System.IO.FileStream ".\_split\_split_$file_count.splt",CreateNew,Write,None
while ($bytes_to_read) {
$bytes_read = $in_file.Read($bytes, 0, [Math]::Min($bytes.Length, $bytes_to_read))
if (!$bytes_read) {
$finished = $true
break
}
$bytes_to_read -= $bytes_read
$out_file.Write($bytes, 0, $bytes_read)
}
$out_file.Dispose()
}
$in_file.Dispose()
}
$i++
while (Test-Path ".\_split\_split_$i.splt") {
$cur_file = (Get-Content ".\_split\_split_$i.splt")
$temp_count = ([regex]::Matches($cur_file, "$pattern")).Count
$match_count += $temp_count
$n = $i - 1
if (Test-Path ".\_split\_split_$n.splt") {
if ($cur_file.Length -ge $pattern.Length) {
$file_transition = $prev_file.Substring($prev_file.Length - ($pattern.Length - 1)) + $cur_file.Substring(0,($pattern.Length - 1))
} else {
$file_transition = $prev_file.Substring($prev_file.Length - ($pattern.Length - 1)) + $cur_file
}
$temp_count = ([regex]::Matches($file_transition, "$pattern")).Count
$match_count += $temp_count
}
$prev_file = $cur_file
$i++
}
} else {
$a
$match_count = ([regex]::Matches($input_file, "$pattern")).Count
}
if ($delete -eq "true") {
Remove-Item ".\_split" -Force -Recurse
}
if ($match_count -ge 1) {
Write-Host "`n`n String '$pattern' found:`n`n $match_count matches!"
} else {
Write-Host "`n`n String '$pattern' not found!"
}
Write-Host `n`n`n`n`n
Pause
This will split a large file into mutliple smaller files, search them for $pattern and count the matches (taking file transitions into account).
It also offers you to delete or keep the splitted files afterwards so you can reuse them and don't have to split the large file every time you run this script.

MAC address string comparison fails

I try to extract a computername from a txt file $pcliste using a string comparison to the MAC address of the local machine. the text file contains:
super-pc 00:15:5D:FF:0B:33
av-client4 00:15:5D:FF:0B:38
temp 00:15:5D:FF:0B:39
I use the following PowerShell code:
$macadresse = Get-WmiObject Win32_NetworkAdapterConfiguration | select macaddress
$macadresse = $macadresse.macaddress
$pcnamen = Get-Content -Path $pcliste
$computername = "TEMP-NAME"
for ($i=0; $i -lt $pcnamen.Length; $i++) {
$string = $pcnamen[$i]
if ($string -match $macadresse) {
write "MAC found!"
$index = $pcnamen[$i].IndexOf(" ")
$computername = $pcnamen[$i].substring(0, $index)
}
}
the MAC adress of my test VM is 00:15:5D:FF:0B:38, but the string comparison in the loop remains false.
For testing I already put the MAC in a string variable instead of extracting it using the Get-WmiObject, and this works.
I also tried to convert the extracted macadress to a string using [string]$macadress.
I assume it's some kind of datatype/objecttype problem that causes the -match to fail.
What about a hash table to put the MAC as key and pc name as value in.
$MyMACs = Get-WmiObject win32_networkadapterconfiguration|Select -Expand MacAddress
$MyMACs
$PcHash = #{}
ForEach ($Row in (Get-Content '.\pcliste.txt')) {
$PcHash.Add($Row.Split(' ')[1],$Row.Split(' ')[0])
}
ForEach($Mac in $MyMACs){
IF ($PcHash[$Mac]){
"Found {0} for MAC {1}" -f $PcHash[$Mac],$Mac
}
}
Or more basic
$MyMACs = Get-WmiObject win32_networkadapterconfiguration|Select -Expand MacAddress
ForEach($Mac in $MyMACs){
Select-String -Path '.\pcliste.txt' -Pattern $MAC|ForEach-Object{$_.Line}
}
try to modify like this:
$string = $pcnamen[$i] -split " "
if ($macadresse -contains $string[1]) {
you can simplify your code like this :
$pcnamen = import-csv $pcliste -Delimiter ' ' -Header Computer, Mac
Get-WmiObject Win32_NetworkAdapterConfiguration | %{
$Mac=$_.macaddress
$pcnamen | where Mac -eq $Mac
}

Powershell script appears to be stuck in else statement and never executes switch

The following Powershell script was wrote to scan and fix unquoted service paths containing white space within the referenced path susceptible to exploitation. The script, when ran ".\Get-ServicePathVulnerabilities" with any of the permitted switches, never executes the if statement for the $Fix (-Fix) switch. Please, review this source code and help me identify the issue, as this is a very convenient script to have in anyone's arsenal.
Function Get-ServicePathVulnerabilities {
[Cmdletbinding()]
Param (
[switch]$Fix
) # End Param
Begin {
$VulnerableServices=#()
if ($Fix){Write-Verbose "Scan Mode: Fix"} else {Write-Verbose "Scan Mode: Audit"}
} # End Begin
Process {
# Gather Services information from WMI
$Services = Get-WmiObject -Class win32_service -Property name,pathname
# Filter out services that have been enclosed with quotations
$UnquotedPath = $Services | Where-Object {$_.PathName -notmatch '"'} | Select Name,PathName
# Loop through services without quotations
foreach ($Path in $UnquotedPath) {
$Drive = $Path.PathName | Split-Path -Qualifier
$Executable = $Path.PathName | Split-Path -Leaf
# Conditional Logic to determine vulnerability
# Note: Some service paths may be unquoted and include spaces, but not vulnerable. They could just be a path to executable (no spaces) with a command line switch parameter that may contain a space.
# To avoid false positives, the logic below will exclude spaces used in any parameters
if( ($Path.PathName -match ' ') -and ($Executable -notmatch ' ') -and ($Path.PathName -notmatch './') ) {
# Vulnerability Found
Write-Warning ("Unquoted Service Path Discovered for " + $Path.Name + " PATH: " + $Path.PathName)
$VulnerableServices += New-Object PSObject -Property #{
ServiceName = $Path.Name
ServicePath = $Path.PathName
HostName = $env:COMPUTERNAME
} # End Object
} # End conditional operators
} # End Foreach Path in UnquotedPath
# Attempt to encapsulate path in quotes if specified
if ($Fix) {
$VulnerableServices | ForEach-Object {
Write-Verbose ("Attempting to fix " + $_.Servicename)
$OriginalPath = $_.ServicePath
$QuotedServicePath = ('"' + $_.ServicePath + '"')
$RegistryLocation = ('HKLM:\SYSTEM\CurrentControlSet\Services\' + $_.ServiceName)
Try {
Set-ItemProperty -Path $RegistryLocation -Name ImagePath -Value $QuotedServicePath -Verbose
$_.ServicePath = $QuotedServicePath
} Catch {
Write-Error ("Unable to fix " + $_.Servicename)
} # End Try/Catch
} # End Foreach object in VulnerableServices
} # End if Fix was Specified
} # End Process
End {
if ($VulnerableServices) {Return $VulnerableServices} else {Write-Verbose "No Unquoted Service path Vulnerabilites have been found"}
} # End End
} # Get-ServicePathVulnerabilites

PowerShell - Enumerating through a collection and change the collection

How it is posible to fix this script?
Yes, I´m changing the collection in the foreach loop and this is the reason for this error.
An error occurred while enumerating through a collection: Collection was modified; enumeration operation may not execute..
At C:\Users\user\Documents\PowerShell\ChangeAllListsV2.ps1:47 char:20
+ foreach <<<< ($list in $webLists)
+ CategoryInfo : InvalidOperation: (Microsoft.Share...on+SPEnumerator:SPEnumerator) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
#Script change in all lists the required field property "testfield" to false
#Part 0 - Configuration
$urlWebApp = "http://dev.sharepoint.com"
$countFound = 0
$countList = 0
$countFoundAndChange = 0
#Part 1 - PreScript
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq "Microsoft.SharePoint.Powershell"}
if ($snapin -eq $null)
{
Write-Host “Loading SharePoint Powershell”
Add-PSSnapin Microsoft.SharePoint.Powershell
}
#Part 2 - Script
$webApp = Get-SPWebApplication $urlWebApp
#$webApp | fl
$webAppSites = $webApp.sites
foreach($site in $webAppSites)
{
Write-Host "***********************************************************************"
Write-Host "Found site: " $site -foreground blue
$siteAllWebs = $site.AllWebs
foreach($web in $siteAllWebs)
{
Write-Host "Found web: " $web -foreground blue
#$web | fl
$webLists = $web.Lists
foreach($list in $webLists)
{
$countList ++
Write-Host "Found list: " $list -foreground blue
#Change list property
$field = $Null
$field = $list.Fields["testfield"]
if($field){
Write-Host "Field found: " $list -foreground green
#Write-Host "in web: " $web -foreground green
$countFound ++
try{
if($field.Required)
{
#######################################################
$field.Required = $False
$field.Update()
#######################################################
$field = $Null
Write-Host "Done!: Change list: " $list -foreground green
$countFoundAndChange ++
}else{
Write-Host "Already!: Change list: " $list -foreground green
}
}
catch{
$field = $Null
Write-Host "Error!: Change list: " $list -foreground red
Write-Host "in web: " $web -foreground red
$_
}
}
}
}
}
Write-Host "Found lists: " $countList
Write-Host "Found lists with column [testfield]: " $countFound
Write-Host "Change lists with column [testfield]: " $countFoundAndChange
The SPListCollection tends to modify the collection when updating its properties (fields, event receivers, etc.). You can use a for-loop instead:
for ($i = 0; $i -lt $webLists.Count; $i++)
{
$list = $web.Lists[$i];
# ...
}
I know this is a pretty old thread. This is for anybody ending up to this page looking for an answer.
The idea is, like other answers suggest, to copy the collection (using the clone() method) to another and iterate "another" and modify the original variable inside the loop without having to use for in place of foreach:
A collection of type ArrayList:
[System.Collections.ArrayList]$collection1 = "Foo","bar","baz"
$($collection1.Clone()) | foreach {
$collection1.Remove("bar")
}
Output:
PS H:\> $collection1
Foo
baz
A collection of type Hashtable:
[System.Collections.Hashtable]$collection2 = #{
"Forum" = "Stackoverflow"
"Topic" = "PowerShell"
}
$($collection2.Clone())| foreach {
$collection2.Remove("Forum")
}
Output:
PS H:> $collection2
Name Value
---- -----
Topic PowerShell
And, a basic array:
[System.Array]$collection3 = 1, 2, 3, 4
$($collection3.Clone()) | foreach {
$collection3[$collection3.IndexOf($_)] = 10
}
Output:
PS H:\> $collection3
10
10
10
10
As long as your collection is not of fixed size.
You can try copying the collection you're currently iterating on to another collection (an array or a list) and then iterate on that new collection.
Something like this:
$collection = #(1, 2, 3, 4)
$copy = #($collection)
$collection[0] = 10
$collection -join " "
$copy -join " "
The code above gives the following output:
10 2 3 4
1 2 3 4
Note that the $copy variable refers to a different collection.
Check: http://soreddymanjunath.blogspot.in/2014/07/collection-was-modified-enumeration.html
Here is anonther example for same issue
if($web.IsMultilingual -eq $true )
{
foreach($cul in $web.SupportedUICultures)
{
if($cul.LCID -ne $webCul.LCID -and $cul.LCID -ne "1033")
{
$web.RemoveSupportedUICulture($cul)
}
}
$web.Update()
}
for the first time it will go through the loop foreach will remove supported culture for frist time, when it comes to loop for the second iteration then it will throw you the exception “Collection was modified; enumeration operation may not execute”,
Solution to Above problem is to Store to values to modified in a Arraylist and try to modify which will fix the problem, Here i am storing Arraylist called enumcul and inserting values into it and modifying it...
$enumcul=New-Object Collections.ArrayList
$i=0
if($web.IsMultilingual -eq $true )
{
foreach($cul in $web.SupportedUICultures)
{
if($cul.LCID -ne $webCul.LCID -and $cul.LCID -ne "1033")
{
$enumcul.Insert($i, $cul)
$i=$i+1
}
}
foreach( $k in $enumcul)
{
$web.RemoveSupportedUICulture($k)
$web.Update()
}

Resources