Powershell Script assistance required - powershell

I'm piping a file's contents to Select-Object and creating two properties for each name, ComputerName and FileExists, where the latter value is the result of Test-Path
Get-Content c:\Users\Admin\Documents\Scripts\Serverlist.txt | `
Select-Object #{Name='ComputerName';Expression={$_}},#{Name='FolderExist';Expression={ Test-Path "\\$_\c$\Data\Repository"}},
#{Name='Size';Expression={$_.Sum}}
I want to return the size of this folder if it exists on each server. How would you do it ?
Tried adding
#{Name='Size';Expression={$_.Sum}}
to my select-object but that does not return any value

I think this is what you are looking for
Get-Content c:\Users\Admin\Documents\Scripts\Serverlist.txt | Select-Object #{Name='ComputerName';Expression={$_}},#{Name='FolderExist';Expression={ Test-Path "\\$_\c$\Data\Repository"}}, #{Name='Size';Expression={ "{0:n2}" -f ((gci -path "\\$_\c$\Data\Repository" -recurse | measure-object -property length -sum).sum /1mb) + " mb" }}

Since at least one calculated property depends on the other, you would have to do at least 2 Select-Object statements, but I would probably use ForEach-Object and New-Object instead:
Get-Content c:\Users\Admin\Documents\Scripts\Serverlist.txt | ForEach-Object {
New-Object psobject -Property #{
'ComputerName' = $_
'FileExists' = ($FileExists = Test-Path ($FilePath = "\\$_\c$\Data\repository"))
'Size' = if($FileExists){ (Get-Item $FilePath).Length } else { $null }
}
}
(Get-Item $FilePath).Length won't get you far if C:\Data\repository is a directory, but you can substitute your own statement inside the if block
For the sake of my future coworkers I would probably avoid doing a one-liner like your example, and write multiple statements like so:
Get-Content c:\Users\Admin\Documents\Scripts\Serverlist.txt | ForEach-Object {
$ComputerName = $_
$FilePath = "\\$ComputerName\c$\Data\repository"
$FileExists = Test-Path $FilePath
if($FileExists){
$Size = Get-Item $FilePath | Select-Object -ExpandProperty Length
} else {
$Size = $null
}
New-Object psobject -Property #{
'ComputerName' = $ComputerName
'FileExists' = $FileExists
'Size' = $Size
}
}

Related

disk check PowerShell with report

I made a PowerShell script to write a report and highlight any disk under 20% of space but the script keeps failing because the size value is not right. Can you please help me?
$Computers = Get-Content -Path C:\Users\gbekari\unbackup\Servers.txt
$results = foreach ($Computer in $Computers){
Get-WmiObject Win32_Volume -Filter "DriveType='3'" -ComputerName $Computer | ForEach {
New-Object PSObject -Property #{
Computername = $computer
date = (Get-Date -format "dd.MM.yy HH:mm")
size = ([Math]::Round($_.Size /1GB,2))
freeSpace = ([Math]::Round($_.FreeSpace /1GB,2))
Status = if ([Math]::Round(100 * $db.FreeSpace / $db.Size) -gt 19 ) {'NONE'} else {'Warning'}
empty = "Diskcheck"
}
}
}
$results | ConvertTo-Csv -NoTypeInformation -Delimiter "|" | % {$_-replace'"',''} | Set-Content -Path C:\Users\gbekari\unbackup\Sers.txt
Lance U. Matthews is on point with his comment, you're trying to reference a property (Size) that does not exist in the Win32_Volume Class and you're referencing a variable that is not defined ($db).
As aside, if you're running PowerShell 3.0 or above, you can construct objects by casting [pscustomobject] instead of using New-Object, this way is more direct and efficient.
Get-WmiObject does not longer exist in newer versions of PowerShell and as stated in the docs:
Starting in PowerShell 3.0, this cmdlet has been superseded by Get-CimInstance
You can also query all computers in parallel, -ComputerName accepts an array of computers.
$Computers = Get-Content -Path C:\Users\gbekari\unbackup\Servers.txt
$results = Get-CimInstance -ClassName Win32_Volume -Filter "DriveType='3'" -ComputerName $Computers | ForEach-Object {
$status = if ([Math]::Round(100 * $_.FreeSpace / $_.Capacity) -gt 19 ) {
'NONE'
}
else {
'Warning'
}
[pscustomobject]#{
Date = Get-Date -format "dd.MM.yy HH:mm"
Size = [Math]::Round($_.Capacity / 1GB, 2)
FreeSpace = [Math]::Round($_.FreeSpace / 1GB, 2)
Status = $status
Empty = "Diskcheck"
}
}
($results | ConvertTo-Csv -NoTypeInformation -Delimiter "|") -replace '"', '' |
Set-Content -Path C:\Users\gbekari\unbackup\Sers.txt
If you don't mind having the computer names in a column named PSComputerName, leave the code as-is, if instead you want to change the column name you can use Select-Object:
($results | Select-Object #{N='ComputerName'; E={ $_.PSComputerName }}, * |
ConvertTo-Csv -NoTypeInformation -Delimiter "|") -replace '"', '' |
Set-Content -Path C:\Users\gbekari\unbackup\Sers.txt

Powershell How to Modify Script to Hardcode " | export-csv c:\temp\filename.csv -notypeinformation"

I have this awesome script I use to generate a list of folders with their assigned security groups and each user in each group.
When I run it, I type .\getfolderacls.ps1 -verbose | export-csv c:\temp\filename.csv -notypeinformation.
That works perfectly, but I'd like to hardcode the | export-csv... part so that I can just run it without the arguments (or are they parameters?).
I tried simply appending | export-csv c:\temp\test.csv -notypeinformation to the bottom of the script, but that throws the error An empty pipe element is not allowed.
Script:
[CmdletBinding()]
Param (
[ValidateScript({Test-Path $_ -PathType Container})]
[Parameter(Mandatory=$false)]
[string]$Path
)
Write-Verbose "$(Get-Date): Script begins!"
Write-Verbose "Getting domain name..."
$Domain = (Get-ADDomain).NetBIOSName
Write-Verbose "Getting ACLs for folder $Path"
Write-Verbose "...and all sub-folders"
Write-Verbose "Gathering all folder names, this could take a long time on bigger folder trees..."
$Folders = Get-ChildItem -Path I:\foldername -Directory -Recurse -Depth 2
Write-Verbose "Gathering ACL's for $($Folders.Count) folders..."
ForEach ($Folder in $Folders)
{ Write-Verbose "Working on $($Folder.FullName)..."
$ACLs = Get-Acl $Folder.FullName | ForEach-Object { $_.Access | where{$_.IdentityReference -ne "BUILTIN\Administrators" -and $_.IdentityReference -ne "BUILTIN\Users" }}
ForEach ($ACL in $ACLs)
{ If ($ACL.IdentityReference -match "\\")
{ If ($ACL.IdentityReference.Value.Split("\")[0].ToUpper() -eq $Domain.ToUpper())
{ $Name = $ACL.IdentityReference.Value.Split("\")[1]
If ((Get-ADObject -Filter 'SamAccountName -eq $Name').ObjectClass -eq "group")
{ ForEach ($User in (Get-ADGroupMember $Name -Recursive | Select -ExpandProperty Name))
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = $Name
User = $User
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = Get-ADUser $Name | Select -ExpandProperty Name
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = $ACL.IdentityReference.Value
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
}
}
Write-Verbose "$(Get-Date): Script completed!"
Your script's output is being produced inside a foreach loop - ForEach ($Folder in $Folders) ... (as opposed to via the ForEach-Object cmdlet, which, unfortunately, is also aliased to foreach).
In order to send a foreach loop's output to the pipeline, you can wrap it in a script block ({ ... }) and invoke it with the dot-sourcing operator (.).
Alternatively, use the call operator (&), in which case the loop runs in a child scope.
Here are simplified examples:
# FAILS, because you can't use a foreach *loop* directly in a pipeline.
PS> foreach ($i in 1..2) { "[$i]" } | Write-Output
# ...
An empty pipe element is not allowed.
# ...
# OK - wrap the loop in a script block and invoke it with .
PS> . { foreach ($i in 1..2) { "[$i]" } } | Write-Output
[1]
[2]
Note: I'm using Write-Output as an example of a cmdlet you can pipe to, solely for the purpose of this demonstration. What's required in your case is to wrap your foreach loop in . { ... } and to follow it with | Export-Csv ... instead of Write-Output.
Using . { ... } or & { ... } sends the output generated inside the loop to the pipeline as it is being produced, one by one, aka in streaming fashion - as (typically) happens with output produced by a cmdlet.
An alternative is to use $(...), the subexpression operator (or #(...), the array-subexpression operator, which works the same in this scenario), in which case the loop output is collected in memory as a whole, up front, before it is sent through the pipeline - this is typically faster, but requires more memory:
# OK - call via $(...), with output collected up front.
PS> $(foreach ($i in 1..2) { "[$i]" }) | Write-Output
[1]
[2]
To spell the . { ... } solution out in the context of your code - the added lines are marked with # !!! comments (also note the potential to improve your code based on Lee_Dailey's comment on the question):
[CmdletBinding()]
Param (
[ValidateScript({Test-Path $_ -PathType Container})]
[Parameter(Mandatory=$false)]
[string]$Path
)
Write-Verbose "$(Get-Date): Script begins!"
Write-Verbose "Getting domain name..."
$Domain = (Get-ADDomain).NetBIOSName
Write-Verbose "Getting ACLs for folder $Path"
Write-Verbose "...and all sub-folders"
Write-Verbose "Gathering all folder names, this could take a long time on bigger folder trees..."
$Folders = Get-ChildItem -Path I:\foldername -Directory -Recurse -Depth 2
Write-Verbose "Gathering ACL's for $($Folders.Count) folders..."
. { # !!!
ForEach ($Folder in $Folders)
{ Write-Verbose "Working on $($Folder.FullName)..."
$ACLs = Get-Acl $Folder.FullName | ForEach-Object { $_.Access | where{$_.IdentityReference -ne "BUILTIN\Administrators" -and $_.IdentityReference -ne "BUILTIN\Users" }}
ForEach ($ACL in $ACLs)
{ If ($ACL.IdentityReference -match "\\")
{ If ($ACL.IdentityReference.Value.Split("\")[0].ToUpper() -eq $Domain.ToUpper())
{ $Name = $ACL.IdentityReference.Value.Split("\")[1]
If ((Get-ADObject -Filter 'SamAccountName -eq $Name').ObjectClass -eq "group")
{ ForEach ($User in (Get-ADGroupMember $Name -Recursive | Select -ExpandProperty Name))
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = $Name
User = $User
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = Get-ADUser $Name | Select -ExpandProperty Name
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
Else
{ $Result = New-Object PSObject -Property #{
Path = $Folder.Fullname
Group = ""
User = $ACL.IdentityReference.Value
FileSystemRights = $ACL.FileSystemRights
}
$Result | Select Path,Group,User,FileSystemRights
}
}
}
}
} | Export-Csv c:\temp\test.csv -notypeinformation # !!!
Write-Verbose "$(Get-Date): Script completed!"

Trying to add PSCustomObjects to an ArrayList on a remote machine

I have some experience with PowerShell, and usually Google or searching forums like these yields the answers when I have questions - but not this time.
I'm trying to collect the number of .log files in a directory on a remote server, then I'd like to store the location (drive letter and folder path) and the count in an array list for later. So far everything is working as I'd expect, but I'm running into trouble adding my PSCustomObjects to the array list. I'm not sure if it's because I'm executing on a remote server or if something else is causing the problem. Here is my code:
$server = Read-Host -Prompt 'Please enter the server name'
[System.Collections.ArrayList]$returnObj = #()
Invoke-Command -ComputerName $server {
$drives = Get-PSDrive -PSProvider FileSystem |
Where-Object {$_.Description -like "ExVol*"} |
Select-Object Root
foreach ($d in $drives) {
Set-Location -Path $d.Root
$folders = Get-ChildItem -Path $d.Root |
Where-Object {$_.Name -like "*.log"} |
Select-Object Name
foreach ($f in $folders) {
$count = (Get-ChildItem -Path $f.Name).Count
$obj = [PSCustomObject]#{
LogFolder = $d.Root.Trim() + $f.Name
LogFileCount = $count
}
Write-Host $obj
$returnObj.Add($obj | Select-Object DatabaseFolder,LogFileCount)
}
}
}
$returnObj
In this format I get a syntax error on the line
$returnObj.Add($obj | Select-Object DatabaseFolder,LogFileCount)
If I change the above line to $returnObj.Add($obj) I avoid the syntax error, but instead I get an error saying I cannot call a method on a null valued expression.
I've tried creating the ArrayList inside the Invoke-Command and I've tried using New-Object instead of PSCustomObject to no avail.
I think your mixing stuff a bit up, this will do:
$returnObj = Invoke-Command -ComputerName $server {
$drives = Get-PSDrive -PSProvider FileSystem |
Where-Object {$_.Description -like "ExVol*"} |
Select-Object Root
foreach ($d in $drives) {
Set-Location -Path $d.Root
$folders = Get-ChildItem -Path $d.Root |
Where-Object {$_.Name -like "*.log"} |
Select-Object Name
foreach ($f in $folders) {
$count = (Get-ChildItem -Path $f.Name).Count
[PSCustomObject]#{
LogFolder = $d.Root.Trim() + $f.Name
LogFileCount = $count
}
}
}
}
$returnObj
The problem is this line:
[System.Collections.ArrayList]$returnObj = #()
is declared outside of the Invoke-Command -ScriptBlock. This means it's not available within the session on the remote machine, and as such can not be used there.
On a side note, you cannot fill an array like you fill a Hashtable with data.
Arrays are filled like $MyArray = #(); $MyArray += 'MyValue'
Hashtables like $MyHash=#{}; $MyHash.SomeKey = 'SomeValue' or as you indicated $MyHash.Add('SomeKey', 'SomeValue')
ArrayLists are filled like [System.Collections.ArrayList]$MyArrayList = #(); $MyArrayList.Add('SomeValue')
I hope this makes it a bit more clear. The return values can always be catched before the Invoke-Command or even before a simple foreach (). For example $result = 0..3 | ForEach-Object {$_} is perfectly valid too.
You need to actually return your object from the remote system to your local system since you cannot use your $returnObj within the remote session.
As an example:
$returnValue = Invoke-Command -ComputerName $server {
$obj = [PSCustomObject]#{
LogFolder = $d.Root.Trim() + $f.Name
LogFileCount = $count
}
#return the object via the pipline
$obj
}
$returnObj.Add($returnValue | Select-Object DatabaseFolder,LogFileCount)
The above example is lacking of proper error handling, therefore you would get an error if the remote system is not reachable but it's a start.

Check Multiple Computers if Path Exists and Export to CSV

I want to make a script that will check whether or not a directory exists on each computer in "computers.csv".
This is what I've come up with:
$results = #()
$computers = Get-Content "C:\Users\me\Desktop\Notes\Computers.csv"
foreach ($computer in $computers) {
$path = Test-Path "\\$computer\c$\Program Files\Folder\"
if ($path -eq $true)
$Output = "True"
else
$Output = "False"
}
$details = #{
Computer_Name = $computer
Output = $Output
}
$results += New-Object PSObject -Property $details
$results |
Select-Object -Property Computer_Name,Output |
Export-Csv c:\results.csv -NoTypeInformation
Script is failing and I'm not entirely sure why. I need the script to export to a CSV due to how many computers are being queried.
You've got several syntax errors. You're missing brackets with if and else, and your foreach closing bracket is in the wrong place. Try this:
$results = #()
$computers = Get-Content "C:\Users\me\Desktop\Notes\Computers.csv"
foreach ($computer in $computers) {
$path = Test-Path "\\$computer\c$\Program Files\Folder\"
If ($path -eq $true) {
$Output = "True"
}
Else {
$Output = "False"
}
$details = #{
Computer_Name = $computer
Output = $Output
}
$results += New-Object PSObject -Property $details
}
$results | select-object -property Computer_Name, Output | Export-csv c:\results.csv -NoTypeInformation
That said, this pattern is one that should be avoided:
$results = #()
foreach ($item in $set) {
$results += $item
}
$results
The problem is that $results += $item copies the entire array into a new array and then adds the new item. It's a huge overhead as the size of the array increases.
Try something like this instead:
Get-Content "C:\Users\me\Desktop\Notes\Computers.csv" | ForEach-Object {
[PSCustomObject]#{
Computer_Name = $_
Output = Test-Path "\\$_\c$\Program Files\Folder\"
}
} | Export-Csv -Path C:\results.csv -NoTypeInformation

If statement invoked twice inside else statement in PowerShell script

I am trying to execute PowerShell script which this code:
function Invoke-InstallationOfANewBuild() {
param (
$PathToTheLocalFolderWhereBuildsAreHeld = "$($env:USERPROFILE)\Desktop\",
$PlaceOnANetworkDriveWhereBuildsAreHeld = "\\r\P\Al\OSystem\D B\20\x64"
)
begin {
Write-Verbose -Message "Searching for a build with the biggest CL number a in build name in local folder." -Verbose
$CheckClNumberOfABuildOnADesktop = Get-ChildItem $PathToTheLocalFolderWhereBuildsAreHeld -Filter *.exe | Where-Object Name -Like '*OSystemInstaller_20*' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1
Write-Verbose -Message "Searching for a build with the biggest CL number in a build name on a network drive." -Verbose
$CheckClNumberOfABuildOnANetworkDrive = Get-ChildItem $PlaceOnANetworkDriveWhereBuildsAreHeld -Filter *.exe | Where-Object Name -NotMatch '.*NoDB\.exe$' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1
Write-Verbose -Message "Comparison of two hash sums. Please, wait." -Verbose
if ($CheckClNumberOfABuildOnADesktop)
{
$GetHashOfFileWhichIsPlacedOnDesktop = Get-MyFileHash $CheckClNumberOfABuildOnADesktop -Algorithm MD5
$GetHashOfFileWhichIsPlacedOnNetworkDrive = Get-MyFileHash $CheckClNumberOfABuildOnANetworkDrive -Algorithm MD5
}
else {
Write-Verbose -Message "There are no O System 20-1 (dev branch) builds in specified local folder. Extracting hash of the newest build in the network folder..." -Verbose
$GetHashOfFileWhichIsPlacedOnNetworkDrive = Get-MyFileHash $CheckClNumberOfABuildOnANetworkDrive -Algorithm MD5
}
if ($GetHashOfFileWhichIsPlacedOnDesktop.MD5 -ne $GetHashOfFileWhichIsPlacedOnNetworkDrive.MD5)
{
Write-Verbose -Message "Hash sum of a file which is placed on the desktop and file in the network drive are different or there is no O System 20-1 build in specified local folder. The newest build will be copied from the network folder to to the local folder." -Verbose
}
else {
Write-Verbose -Message "Hash sum of a file which is placed on the desktop and a file on the network drive are the same. No need to copy anything." -Verbose
}
}
process {
if ($GetHashOfFileWhichIsPlacedOnDesktop.MD5 -eq $GetHashOfFileWhichIsPlacedOnNetworkDrive.MD5){
Write-Verbose -Message "Installation... Please, wait." -Verbose
Get-ChildItem $PathToTheLocalFolderWhereBuildsAreHeld -Filter *.exe | Where-Object Name -Like '*OSystemInstaller_20*' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1 | ForEach-Object { & $_ -s2 -sp"-SilentInstallation=standalone -UpdateMaterials=yestoall -UpgradeDBIfRequired=yes"}
}
else {
Write-Verbose -Message "The newest build doesn't exist in specified folder. Downloading, please wait." -Verbose
$SelectTheNewestBuildInFolder = Get-ChildItem $PlaceOnANetworkDriveWhereBuildsAreHeld -Filter *.exe | Where-Object Name -NotMatch '.*NoDB\.exe$' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1 | Copy-Item -Destination $PathToTheLocalFolderWhereBuildsAreHeld
}
$HashNumberOfCopiedBuild = Get-MyFileHash $SelectTheNewestBuildInFolder -Algorithm MD5
if ($HashNumberOfCopiedBuild.MD5 -eq $GetHashOfFileWhichIsPlacedOnNetworkDrive.MD5) {
Write-Verbose -Message "Hash sum of the copied file and hash sum of original file are the same. Builds are the same." -Verbose
Write-Verbose -Message "Installation... Please, wait." -Verbose
Get-ChildItem $PathToTheLocalFolderWhereBuildsAreHeld -Filter *.exe | Where-Object Name -Like '*OSystemInstaller*' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1 | ForEach-Object {& $_ -s2 -sp"-SilentInstallation=standalone -UpdateMaterials=yestoall -UpgradeDBIfRequired=yes"}
}
else {
Write-Verbose -Message "Hash sum of the copied file and hash sum of original file are different. Builds are the same." -Verbose
} # [Block moved]
}
}
Invoke-InstallationOfANewBuild
But the if statement in last else statement works twice (so that installation process is invoked twice). How can I put if statement inside else statement so that it can be invoked only once? Example
1) If value is true in the else than execute installation and stop the script
2) If value is false in the else than move to if in else and execute installation from there.
process {
if ($GetHashOfFileWhichIsPlacedOnDesktop.MD5 -ne $GetHashOfFileWhichIsPlacedOnNetworkDrive.MD5) {
Get-ChildItem $PlaceOnANetworkDriveWhereBuildsAreHeld -Filter *.exe | Where-Object Name -NotMatch '.*NoDB\.exe$' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1 | Copy-Item -Destination $PathToTheLocalFolderWhereBuildsAreHeld
}
$CheckClNumberOfABuildOnADesktop = Get-ChildItem $PathToTheLocalFolderWhereBuildsAreHeld -Filter *.exe | Where-Object Name -NotMatch '.*NoDB\.exe$' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1
$HashNumberOfTheCopiedBuild = Get-MyFileHash $CheckClNumberOfABuildOnADesktop -Algorithm MD5
if ($HashNumberOfTheCopiedBuild.MD5 -eq $GetHashOfFileWhichIsPlacedOnNetworkDrive.MD5) {
Write-Verbose -Message "Installation... Please, wait." -Verbose
Get-ChildItem $PathToTheLocalFolderWhereBuildsAreHeld -Filter *.exe | Where-Object Name -Like '*OrthoSystemInstaller*' | ForEach-Object {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort-Object No -Descending | Select-Object -ExpandProperty Name -First 1 | ForEach-Object {& $_ -s2 -sp"-SilentInstallation=standalone -UpdateMaterials=yestoall -UpgradeDBIfRequired=yes"}
}
else {
Write-Verbose -Message "H" -Verbose
}
}
}
All I did - remove installation from first if and put to the second if.