Powershell script Issue string - string

The $Vendor is not recognised when pass it as paramater for creating folder in the console.It gives error String input not in correct format.If I pass any string manually it is recognizing and creating folder with that name.I tried parsing $Vendor to string.Could you help me?
#function to fetch folder information
function APP-Parameters($appfolder)
{
Write-Output $appfolder
$data = $appfolder.split("-")
$APPLICATIONNAME = $data[2]+$data[3]+$data[4]+$data[5]+$data[6]+$data[0]
$DEPLOYMENTTYPENAME = $data[5]+$data[6]+$data[0]
$obj= new-object psobject
$obj | Add-Member Noteproperty APPID $data[0]
$obj | Add-Member Noteproperty APPNAME $data[2]
$obj | Add-Member Noteproperty VERSION $data[3]
$obj | Add-Member Noteproperty LANGUAGE $data[4]
$obj | Add-Member Noteproperty VARIANT $data[5]
$obj | Add-Member Noteproperty RELEASEVERSION $data[6]
#$obj | Add-Member Noteproperty APPLICATIONNAME $APPLICATIONNAME
#$obj | Add-Member Noteproperty DEPLOYMENTTYPENAME $DEPLOYMENTTYPENAME
switch ($data[1])
{
"MS"
{
$obj | Add-Member Noteproperty VENDOR "Microsoft"
break
}
default {
$obj | Add-Member Noteproperty VENDOR $data[1]
}
}
Return $obj
}
#Function for Creating the Folder
Function New-CMFolder
{
[CmdLetBinding()]
Param(
[Parameter(Mandatory=$True,HelpMessage="Please Enter Site Server Site code")]
$SiteCode,
[Parameter(Mandatory=$True,HelpMessage="Please Enter Site Server Name")]
$SiteServer,
[Parameter(Mandatory=$True,HelpMessage="Please Enter Folder Name")]
$Name,
[Parameter(Mandatory=$True,HelpMessage="Please Enter Folder Object Type")]
$ObjectType,
[Parameter(Mandatory=$True,HelpMessage="Please Enter parent folder ID")]
$ParentContainerNodeId
)
$Arguments = #{Name = $Name; ObjectType = "$ObjectType"; ParentContainerNodeId = "$ParentContainerNodeId"}
Try{
Set-WmiInstance -Namespace "root\sms\Site_$SiteCode" -Class "SMS_ObjectContainerNode" -Arguments $Arguments `
-ComputerName $SiteServer -ErrorAction STOP
}
Catch{
$_.Exception.Message
"THE VENDOR FOLDER PRESENT" + $Name | out-file C:\Windows\Logs\test.txt -append
}
}
#Function for Fetching the node
function Get-ParentNode($ConsoleFolder)
{
$Confolder=$ConsoleFolder.split("\")
$ParentContainerNodeId="0"
$len=$Confolder.length
For ($i=0; $i -lt $len; $i++)
{
New-CMFolder -SiteCode "PR1" -SiteServer $SiteServer -Name $Confolder[$i] -ObjectType "6000" -ParentContainerNodeId $ParentContainerNodeId
$Parent_Node=Get-WMIObject -ComputerName $SiteServer -Namespace "root\sms\site_$siteCode" -Query "Select * From SMS_ObjectContainerNode" | Where { ($_.Name -like $Confolder[$i]) -and ($_.ObjectType -like '6000') }
$ParentContainerNodeId = $Parent_Node.ContainerNodeID
}
$len=$len-1
$Parent_Node=Get-WMIObject -ComputerName $SiteServer -Namespace "root\sms\site_$siteCode" -Query "Select * From SMS_ObjectContainerNode" | Where { ($_.Name -like $Confolder[$len]) -and ($_.ObjectType -like '6000') }
$ParentContainerNodeId1 = $Parent_Node.ContainerNodeID
$obj= new-object psobject
$obj | Add-Member Noteproperty ParentContainerNodeId $ParentContainerNodeId1
Return $obj
}
#Global Variable Declaration
$SiteCode="PR1"
$SiteServer="Babusccmlab1"
$ObjectType="6000"
$ConsoleFolder="Global Package\SRT-Packages"
$ExportFilesLocation="\\babusccmlab1\c$\AZTESTPACKAGES\*.*"
$ParentContainerNodeId="0"
$Parent_Node=Get-ParentNode($ConsoleFolder)
$Parent_Node=$Parent_Node.ParentContainerNodeID
$ProductionServer="\\SMSSITESERVER\AZTESTPACKAGES\"
Set-Location C:\
$a= Get-Childitem -path $ExportFilesLocation -include *.zip
cd "Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin"
$Setsite = $SiteCode + ":"
CD $Setsite
foreach($x in $a) {
If($x.name -match "^[0-9]{6}\-[a-z0-9-_+']*\-[a-z0-9-_+']*\-[a-z0-9.-_+']*\-[a-z0-9-_+']*\-[a-z0-9-_+']*\-[a-z0-9-_+']*\.ZIP")
{
$appfoldername = $x.name.TrimEnd(".zip")
$APPID=APP-Parameters($appfoldername) | SELECT APPID | out-file C:\Windows\Logs\test.txt -append
$VENDOR=APP-Parameters($appfoldername)
[String]$VENDOR = $VENDOR.Vendor | out-file C:\Windows\Logs\test.txt -append
[String]$u = $Vendor | out-file C:\Windows\Logs\test.txt -append
$APPNAME=APP-Parameters($appfoldername) | SELECT APPNAME | out-file C:\Windows\Logs\test.txt -append
$LANGUAGE=APP-Parameters($appfoldername) | SELECT LANGUAGE | out-file C:\Windows\Logs\test.txt -append
$VARIANT=APP-Parameters($appfoldername) | SELECT VARIANT | out-file C:\Windows\Logs\test.txt -append
$SCCM_APPNAME=APP-Parameters($appfoldername) | SELECT APPLICATIONNAME | out-file C:\Windows\Logs\test.txt -append
#$SCCM_DEPLOYMENTTYPENAME=APP-Parameters($appfoldername) | SELECT DEPLOYMENTTYPENAME
#$RELEASEVERSION=APP-Parameters($appfoldername) | SELECT RELEASEVERSION
"--------" + $x.name + "--------" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
"THE FOLDER STRUCTURE MATCH" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
#----------------------------------------------------SCCM2012 CONSOLE MANAGEMENT---------------------------------------------------------
New-CMFolder -SiteCode $SiteCode -SiteServer $SiteServer -Name $Vendor -ObjectType $ObjectType -ParentContainerNodeId $Parent_Node
} else
{
"--------" + $x.name + "--------" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
"THE FOLDER STRUCTURE DOES NOT MATCH" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
"" | out-file C:\Windows\Logs\test.txt -append
}
}

What line is it giving you the error on?
This line:
[String]$VENDOR = $VENDOR.Vendor | out-file C:\Windows\Logs\test.txt -append
doesn't make any sense. That pipe operation isn't going to return anything, so $VENDOR is going to be null.

Related

How to split different values in powershell by a line

With this script i am able to fetch all the Tags that a VM has but i want that in output the each key and its value should be separated by a line in the way that each key and its value appears on different lines like this
reference image
# Sign into Azure Portal
connect-azaccount
# Fetch the Virtual Machines from the subscription
$azureVMDetails = get-azvm
# Fetch the NIC details from the subscription
$azureNICDetails = Get-AzNetworkInterface | ?{ $_.VirtualMachine -NE $null}
#Fetching Virtual Machine Details
$virtual_machine_object = $null
$virtual_machine_object = #()
#Iterating over the NIC Interfaces under the subscription
foreach($azureNICDetail in $azureNICDetails){
#Fetching the VM Name
$azureVMDetail = $azureVMDetails | ? -Property Id -eq $azureNICDetail.VirtualMachine.id
#Fetching the VM Tags
foreach($azureDetail in $azureVMDetails) {
$vm_tags = $azureVMDetail| Select-Object -Property (
#{name='Tags'; expression = {($_.tags.GetEnumerator().ForEach({ '{0} : {1}' -f $_.key, $_.value }) -join ';')}}
)
}
#VM Details export
$virtual_machine_object_temp = new-object PSObject
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "name" -Value $azureVMDetail.Name
$virtual_machine_object_temp | add-member -membertype NoteProperty -name "comments" -Value ($vm_tags.Tags -join ';')
$virtual_machine_object += $virtual_machine_object_temp
}
#Report format and path
$virtual_machine_object | Export-Csv "C:\Users\JOHN\Desktop\Inventory\Final Scripts\VM_details_$(get-date -f dd.MM.yyyy).csv" -NoTypeInformation -Force
I tried to reproduce the same in my environment and got the results successfully by using the below PowerShell script:
$vmdeatil = Get-AzVm -Name testvm | Select -ExpandProperty Tags
$value = $vmdeatil
foreach($i in 0..($value.Count -1))
{
$ErrorActionPreference = ‘SilentlyContinue’
[array]$report += [pscustomobject] #{
key = $key[$i]
name = $value[$i]
}
}
$report | Export-Csv -Path "C:\Users\ruk1.csv" -NoTypeInformation
Response:
The output is successfully exported in the csv file like below:

Separating values of a column in a CSV in powershell

I have multiple files contain a persons Fullname in a single cell. I would like to separate these names into two columns - first name and Surname
the code I have used to separate values worked in a previous iteration of the script I had but now no longer works
I can't pinpoint where the error lies, can anyone advise?
$path = 'C:\MAY2019correct'
#XYZ
$excelOut = Join-Path -Path $path -ChildPath 'XYZ.csv'
$completedFile = Join-Path -Path $path -ChildPath 'Completed-XYZ.csv'
$defaultValue = 'ABC'
$filter = '*XYZ*'
$excelFile = Get-ChildItem -Path $path -Filter $filter -File |
Select-Object -First 1
$allstaff = #()
if ($excelFile) {
$excel = New-Object -ComObject Excel.Application -Property #{Visible =
$false}
# Open the file
$workbook = $excel.Workbooks.Open($excelFile.FullName)
# Activate the first worksheet
$sheet = $workbook.Sheets.Item(1)
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the first row
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the 2 row
[void]$sheet.Cells.Item(1, 1).EntireRow.Delete() # Delete the 3 row
$workbook.SaveAs($excelOut,6)
# Close workbook and save changes
$workbook.Close($true)
# Quit Excel
$excel.Quit()
# clean-up Com objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
$headers = 'Element Name','Surname','EmployeeNo','Amount','YTD'
# import the csv file and select all the above headers plus one that is created using a calculated property
$csv = Import-Csv -Path $excelOut -Header $headers -UseCulture | Select-Object *, #{Name = 'Paycentre'; Expression = {$defaultValue}}|
Write-Host "Creating completed csv file '$completedFile'"
$csv | Export-Csv -Path $completedFile -UseCulture -Force -
NoTypeInformation
}
else {
Write-Warning "Could not find a file using filter '$filter' in path
'$path'"
}
foreach($staff in $completedFile)
{
#Get the values from the CSV for this row
$Surname = $staff.Surname
$Surname = $Surname.Substring(0, $Surname.lastIndexOf(' '))
$Initial = $staff.Surname
$Initial = $Initial.Substring($Initial.lastIndexOf(' ') + 1 )
$Firstname = $staff.Surname
$Firstname = $Firstname.Substring($Initial.lastIndexOf(' ') + 1 )
$EmployeeNo = $staff.EmployeeNo
$NINumber = $staff.NINumber
$Amount = $staff.Amount
$Paycentre = $staff.Paycentre
$staff2 = New-Object System.Object
$staff2 | Add-Member -MemberType NoteProperty -Name "Surname" -Value $Surname
$staff2 | Add-Member -MemberType NoteProperty -Name "FirstName" -Value $Firstname
$staff2 | Add-Member -MemberType NoteProperty -Name "EmployeeNo" -Value $EmployeeNo
$staff2 | Add-Member -MemberType NoteProperty -Name "NINumber" -Value $NINumber
$staff2 | Add-Member -MemberType NoteProperty -Name "Amount" -Value $Amount
$staff2 | Add-Member -MemberType NoteProperty -Name "FirstName" -Value $Initial
$staff2 | Add-Member -MemberType NoteProperty -Name "Paycentre" -Value $Paycentre
#add to array
$allstaff += $staff2
}
$allstaff | Export-Csv -NoTypeInformation -Path $completedFile
The first thing I see is that your foreach loop is iterating over the $completedFile variable which appears to be a file path, not a collection.
Should it be foreach ($staff in $csv) instead?
Also, be very wary of dealing with names in code. It's super easy to make poor assumptions that break things. See Falsehoods Programmers Believe About Names for more info there.

Code to grab file data into PSOObject and sort by LastWriteTime

I am looking to recursively grab a list of recently modified files under two network drives, sort them in descending date order, and make some edits to the CSV file to tidy the list for Excel
I have cobbled the code below from a number of sources (I am a powershell beginner) and it is now doing what I need (i.e. producing a list).
I need help in going a step further, I cannot sort the resultant CSV file by file last write time date, is this because my array is expecting text rather than a numeric field?
I also am returning the domain name as well as the file owner with ((Get-ACL $_.FullName).Owner). I tried using Replace to cut down the string, but had no luck with this approach.
$arr = #()
$days_to_check=$(Get-Date).AddDays(-28)
$items = #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue | where { $_.LastWriteTime -gt $days_to_check})
$items += #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue |
where { $_.LastWriteTime -gt $days_to_check})
$items | Foreach {
$obj = New-Object PSObject -prop $hash
$obj | Add-Member NoteProperty FullName $_.FullName
$obj | Add-Member NoteProperty Directory $_.Directory
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty LastTime $_.LastWriteTime
$obj | Add-Member NoteProperty Owner ((Get-ACL $_.FullName).Owner)
$arr += $obj
}
$arr | Format-List
$arr | Sort-Object -Property LastTime -Descending
$arr | Export-CSV -notypeinformation C:\temp\filenamesFO.csv
CSV file sorted by date field
You did sort your array in the output but that's all you did.
If you want to actually export it that way, you have to assign the sort to $arr
Replace
$arr | Sort-Object -Property LastTime -Descending
with
$arr = $arr | Sort-Object -Property LastTime -Descending
You can remove the Owner domain using the following Replace -replace '(.*\\)(.*)','$2'
Here's a complete example implementing the changes mentionned above.
$arr = new-object -TypeName 'System.Collections.Generic.List[PSObject]'
$days_to_check=$(Get-Date).AddDays(-28)
$items = #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue | where { $_.LastWriteTime -gt $days_to_check})
$items += #(Get-ChildItem '\\ND\dir 1\*.*' -Recurse -ErrorAction SilentlyContinue |
where { $_.LastWriteTime -gt $days_to_check})
Foreach ($item in $items) {
$obj = [PSCustomObject]#{
FullName = $item.FullName
Directory = $item.Directory
Name = $item.Name
LastTime = $item.LastWriteTime
Owner = (Get-ACL $item.FullName).Owner -replace '(.*\\)(.*)','$2'
}
$arr.add($obj)
}
$arr = $arr | Sort-Object -Property LastTime -Descending
#$arr | Format-List
$arr | Export-CSV -notypeinformation C:\temp\filenamesFO.csv
I made some additional changes:
Instead of using an array, I used a List of PSObject. If you have a lot of files, the processing time will be improved in comparison with an array.
I used the PSCustomObject declaration just to show an alternative to all those Add-member. I find it cleaner but it is up to you in the end.

Display the difference of Excel columns with PowerShell

I would like to get the difference in the columns in as a table but I only can do a comparison with two columns and it doesn't display all the columns. I need to see in which column the cell is not present in the first column.
The file:
ComputerName OtherComputerName OtherComputer AndAgain
infra-1 infra-852 infra-2 infra-99
infra-98 infra-85 infra-44 infra-23
infra-5 infra-8 infra-1 infra-1
infra-2 infra-55 infra-8 infra-70
infra-62 infra-5 infra-852 infra-5
The current result:
ComputerName OtherComputerName OtherComputer AndAgain
------------ ----------------- ------------- --------
I would like to get this as result in PowerShell:
ComputerName OtherComputerName OtherComputer AndAgain
------------ ----------------- ------------- --------
infra-1 infra-852 infra-99
infra-98 infra-85 infra-44 infra-23
infra-5 infra-8
infra-2 infra-55 infra-8 infra-70
infra-62 infra-852
Edit
I have some errors too when I run this code.
The script:
$csv = Import-Csv .\test1.csv -Delimiter ';'
$ref = #($csv.ComputerName)
foreach ($row in $csv) {
foreach ($col in 'OtherComputerName', 'OtherComputer', 'AndAgain') {
if ($ref -contains $row.$col) { $row.$col = '' }
}
}
$table = #()
$file = Get-Content .\test1.csv
$file = $file -replace(" "," ")
$file = $file -replace(" "," ")
$file = $file -replace(" "," ")
$file = $file -replace(" - "," ")
[string[]]$a = Import-Csv '.\test1.csv' | select -Expand ComputerName
[string[]]$b = Import-Csv '.\test1.csv' | select -Expand OtherComputerName
[string[]]$c = Import-Csv '.\test1.csv' | select -Expand OtherComputer
[string[]]$d = Import-Csv '.\test1.csv' | select -Expand AndAgain
$b | ? {$a -notcontains $_}
$c | ? {$a -notcontains $_}
$d | ? {$a -notcontains $_}
foreach ($line in $file) {
$lineb = $line -split(" ")
$obj = New-Object PSObject
$obj | Add-Member -Name "ComputerName" -MemberType NoteProperty -Value $lineb[1]
$obj | Add-Member -Name "OtherComputerName" -MemberType NoteProperty -Value $lineb[1]
$obj | Add-Member -Name "OtherComputer" -MemberType NoteProperty -Value $lineb[2]
$obj | Add-Member -Name "AndAgain" -MemberType NoteProperty -Value $lineb[3]
$table += $obj
}
$table | ft -AutoSize
You need to read the values of the first column into an array, compare the values of the other columns against that array, and clear matching fields:
$csv = Import-Csv .\test1.csv -Delimiter ';'
$ref = #($csv | Select-Object -Expand ComputerName)
foreach ($row in $csv) {
foreach ($col in 'OtherComputerName', 'OtherComputer', 'AndAgain') {
if ($ref -contains $row.$col) { $row.$col = '' }
}
}

Output Value from select-object calculated value

I've used a hash table to calculate some values for my VMWare inventory script, but now when I output the data, it records it as a key/value pair. I'd like to dump just the value. When I simply take what I'm handed that works fine, but when I get picky PS starts to stonewall me. :-)
Here is the relevant part of the script.
foreach ($machine in $vmList) {
$vmname = $machine.Name
$properties = #{
'Name'=Get-VM $vmname | Select -ExpandProperty Name
'RAM'=Get-VM $vmname | Select -ExpandProperty MemoryGB
'CpuCount'=Get-VM $vmname | Select -ExpandProperty NumCpu
'UsedDiskGB'=Get-VM $vmname | Select-Object #{n="UsedDiskGB"; e={[math]::Round( $_.UsedSpaceGB, 3 )}}
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}
'Networks'=Get-VM $vmname | Select-Object #{n="Networks"; e={(Get-NetworkAdapter -VM $_ |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '}}
'OS'=(Get-VM -Name $vmname | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}
How do I get UsedDiskGB, Networks and TotalDiskGB to display just the value instead of something like '#{TotalDiskGB=80}'? Ram, OS, CpuCount and Name work exactly as desired already.
Also, suggestions on doing this in a faster way are welcome. I'm sure all these calls can be done better. I had it done in a single line, but then they asked for OS to be added and that changed everything.
Easy, but bad way:
In the expression pipe to |Select -ExpandProperty <property name> to get just the value. Such as:
'TotalDiskGB'=Get-VM $vmname | Select-Object #{n="TotalDiskGB"; e={[math]::Round((Get-HardDisk -vm $_ | Measure-Object -Sum CapacityGB).Sum)}}|select -expand totaldiskgb
The better way:
Structure your properties better to start with. Try this:
'TotalDiskGB'= [math]::Round((Get-HardDisk -vm (Get-VM $vmname) | Measure-Object -Sum CapacityGB).Sum)
The reason you're having issues is because you are creating a PSCustomObject with your Select, and Totaldiskgb is a property of that object. You don't want to make an object, you just want the value of that property.
Edit: Thank you to #briantist for pointing out that Get-VM $vmname should be called once, and stored as an object to be used later, rather than called for each time it is needed for a member of $Properties. For example:
foreach ($machine in $vmList) {
$vmname = $machine.Name
$vmobject = Get-VM $vmname
$properties = #{
'Name'=$vmobject | Select -ExpandProperty Name
'RAM'=$vmobject | Select -ExpandProperty MemoryGB
'CpuCount'=$vmobject | Select -ExpandProperty NumCpu
'UsedDiskGB'=[math]::Round( $vmobject.UsedSpaceGB, 3 )
'TotalDiskGB'=[math]::Round((Get-HardDisk -vm $vmobject | Measure-Object -Sum CapacityGB).Sum)
'Networks'=(Get-NetworkAdapter -VM $vmobject |Sort-Object NetworkName |Select -Unique -Expand NetworkName) -join '; '
'OS'=($vmobject | Get-View).summary.config.guestFullName
}
$object=New-Object -TypeName PSObject -Prop $properties
Export-Csv -Path $WorkDir\vms.csv -Append -Encoding UTF8 -InputObject $Object
Write-Output $Object
}

Resources