Stumped on a problem here - running Powershell 1.0
Code (Assume an ip address which is valid is being passed in):
$ips = #(Import-CSV $attachmentLocation)
foreach ($ip in $ips){
$ipAddress = $ip.IPAddress
$length = $ipaddress.length
write-host "Length is: ($length)"
if(Test-Connection -ComputerName $ipAddress -Count 1 -ea silentlycontinue) {
write-host $ipAddress
$hostData = ([Net.Dns]::GetHostByAddress($ipAddress)).HostName
}
}
Output:
Length is: (11)
10.xx.xx.xx
Exception calling "GetHostByAddress" with "1" argument(s): "The requested name is valid, but no data of the requested type was found"
At FileName:13 char:43
+ $hostData = ([Net.Dns]::GetHostByAddress <<<< ($ipAddress)).HostName
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
If I run the following it works fine - seems to be data type issue (im passing in a string value):
$hostData = ([Net.Dns]::GetHostByAddress("10.xx.xx.xx")).HostName
Working Code:
$ipAddress = "10.xx.xx.xx"
$hostData = ([Net.Dns]::GetHostByAddress($ipAddress)).HostName
Answer:
Issue was with the ActiveDirectory Domain DNS resolution not the command, while some IP addresses were pingable they were not resolving properly on machine where the script was run. This was causing the error 'no data of the requested type was found' refers to the fact it couldn't resolve the IP to a DNS name.
I've got two ideas you could try:
GetHostByAddress() supports string and ipaddress. So try casting to ipaddress-type before running the function.
if(Test-Connection -ComputerName $ipAddress -Count 1 -ea silentlycontinue) {
write-host $ipAddress
$hostData = ([Net.Dns]::GetHostByAddress(([ipaddress]$ipAddress))).HostName
}
If you're on PS 1.0, then your first priority should be to upgrade the machines to at least PowerShell 2.0. Nothing works well in PS 1.0.
Running PS3, I get the error shown when traversing subnets on our domain. Especially remote locations.
I'm checking 5 different C-class subnets on our domain to make sure there aren't devices we don't have in AD.
It's also possible some devices aren't PCs with a hostname: routers, switches, firewalls, scanners, and the like.
When my code gets to my local office, no error.
I'm not using a file, instead I generate the subnets via code in the script.
Related
I am developing a couple of PowerShell scripts to help speed up the process of migrating user data from an old workstation to a new one. Currently trying to make one to help with retrieving and then deploying mapped network drives and have hit a snagged with the deployment aspect. I am new to PowerShell and learning as I go along using the ISE to help spot some of the problem areas the script has. Here is a copy of what the script currently looks like and the error I am receiving when trying to run it on the machine.
# Import drive list.
$mappedDrives = Import-Csv C:\Users\########\Desktop\WIP_Scripts\MasterCopy\mappedDrives.csv
$mappedDrives | %{$_ -replace ":"}
foreach ($Name in $mappedDrives) {
New-PSDrive -Name $Name.Name -PSProvider FileSystem -Root "ProviderName" -Persist -ErrorAction Continue
}
Once I have it working Ill make the edits for where the import comes from. The errors I am currently receiving are:
New-PSDrive : Cannot process the drive name because the drive name contains one or more of
the following characters that are not valid: ; ~ / \ . :
At C:\Users\#######\Desktop\WIP_Scripts\MasterCopy\ImportMappedDrives.ps1:8 char:5
+ New-PSDrive -Name $Name.Name -PSProvider FileSystem -Root "Provid ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-PSDrive], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.NewPSDriveCommand
New-PSDrive : Cannot process the drive name because the drive name contains one or more of
the following characters that are not valid: ; ~ / \ . :
At C:\Users\#######\Desktop\WIP_Scripts\MasterCopy\ImportMappedDrives.ps1:8 char:5
+ New-PSDrive -Name $Name.Name -PSProvider FileSystem -Root "Provid ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-PSDrive], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.NewPSDriveCommand
New-PSDrive : Cannot process the drive name because the drive name contains one or more of
the following characters that are not valid: ; ~ / \ . :
At C:\Users\#######\Desktop\WIP_Scripts\MasterCopy\ImportMappedDrives.ps1:8 char:5
+ New-PSDrive -Name $Name.Name -PSProvider FileSystem -Root "Provid ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-PSDrive], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.NewPSDriveCommand
For the script used to retrieve the drive information:
$mappedDrives = #()
$Name = Get-WmiObject -ClassName Win32_MappedLogicalDisk | Select Name, ProviderName
foreach ($Name in $Name) {
if ($Name. ProviderName) {
$mappedDrives += Select-Object Name, ProviderName -InputObject $Name
}
}
$mappedDrives | Export-Csv mappedDrives.csv
MappedDrives.csv Output
Also attached is what the mappeddrives.csv output looks like for the retrieval. I thought that the csv file may be causing the invalid character arguements since the Name found within the csv file includes the ":" character. Also I am a bit confused on whether or not it will be able to see the "ProviderName" within the csv file or if I need to declare it in order for the script to add it to its argument. Again I am extremely new to Powershell so lots of what I have written down is what I have found from this site, Microsoft, or other blogs/forums and trying to Frankenstein together a working script. Any feedback on how to improve or get this to work and/or why using another method would be better in this situation would be greatly appreciated.
###Revision 1###
Utilizing the new script provided by RetiredGeek
# Import drive list.
$CFSArgs = #{PropertyNames = "Name", "ProviderName"
Delimiter = ','}
$MappedDrives = (Get-Content "G:\BEKDocs\Scripts\Test\mappedDrives.csv") |
ConvertFrom-String #CFSArgs
for ($cnt = 1; $cnt -lt $MappedDrives.count; $cnt++) {
$NPSDArgs =
#{Name = $(($MappedDrives[$cnt].Name).Substring(0,1))
PSProvider = "FileSystem"
Root = "$($MappedDrives[$cnt].ProviderName)"
Persist = $True
ErrorAction = "Continue"
}
New-PSDrive #NPSDArgs
}
I am now receiving the following error:
New-PSDrive : When you use the Persist parameter, the root must be a file system location
on a remote computer.
At C:\Users\######\Desktop\MasterCopy\Test2.ps1:16 char:9
+ New-PSDrive #NPSDArgs
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (":PSDriveInfo) [New-PSDrive], NotSupported
Exception
+ FullyQualifiedErrorId : DriveRootNotNetworkPath,Microsoft.PowerShell.Commands.NewPSD
riveCommand
The two questions I have now are:
Would it be more appropriate to use "Net use" instead of "New-PSDrive" for what I am trying to achieve(which is mapping a network drive to a computer using the cvs file created)?
If the use of the New-PSDrive cmdlet is a non-issue how do I rectify the error the script is currently outputting?
Thanks again to RetiredGeek and Theo for your inputs.
FT,
You need to evaluate your arguments in the New-PSDrive line.
Using Substring there eliminates code and makes it more efficient.
I had problems using Import-CSV so I switched to Get-Content and adjusted
# Import drive list.
$CFSArgs = #{PropertyNames = "Name", "ProviderName"
Delimiter = ','}
$MappedDrives = (Get-Content "G:\BEKDocs\Scripts\Test\mappedDrives.csv") |
ConvertFrom-String #CFSArgs
for ($cnt = 1; $cnt -lt $MappedDrives.count; $cnt++) {
$NPSDArgs =
#{Name = $(($MappedDrives[$cnt].Name).Substring(0,1))
PSProvider = "FileSystem"
Root = "$($MappedDrives[$cnt].ProviderName)"
Scope = "Global"
Persist = $True
ErrorAction = "Continue"
}
New-PSDrive #NPSDArgs -WhatIf
}
I used the -WhatIf parameter since I don't have your targets available but it showes what would have been done.
Output:
What if: Performing the operation "New drive" on target "Name: X Provider: Micro
soft.PowerShell.Core\FileSystem Root: \\hapi\desktop$\Decommission Log".
What if: Performing the operation "New drive" on target "Name: Y Provider: Micro
soft.PowerShell.Core\FileSystem Root: \\gonzo\Temp\AZ".
What if: Performing the operation "New drive" on target "Name: Z Provider: Micro
soft.PowerShell.Core\FileSystem Root: \\gonzo\Temp\001".
PS>
Update 1:
Further testing on my network (Peer-to-Peer) reveals that adding the Scope parameter (see above) will create the mapping, even though you get the same message, and it will last until you Reboot! It does NOT however persist after the reboot so it is not doing what it should. I still don't understand why it the message is displayed as the root is on another computer. Also, the mapping doesn't show in File Explorer although I can open a command prompt and successfully do a DIR on the drive.
Update 2:
I tried another test mapping to my Synology NAS and it worked w/o the error message. But, alas it did NOT persist a reboot!
I am trying to update an Address Book Policy on Exchange Online.
Idea is that I parse some Address Lists and save these into a variable.
These could be passed into the Set-AddresBookPolicy.
So I start off with parsing these adresses:
$AddressLists = (Get-AddressList).Id | ? {$_ -like "*Company_1*"}
This results an array like \Company_1_Users, \Company_1_Contacts, \Company_1_DLs as expected.
I apply these with
Set-AddressBookPolicy -Identity "Company1" -AddressLists $AddressLists `
-RoomList "C1_Rooms" -GlobalAddressList "C1_GAL" -OfflineAddressBook "C1_OAB"
Result is an error:
WARNING: An unexpected error has occurred and a Watson dump is being generated: The operation can't be performed on this object because its status isn't valid.
The operation can't be performed on this object because its status isn't valid.
+ CategoryInfo : NotSpecified: (:) [Set-AddressBookPolicy], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Exchange.Management.SystemConfigurationTasks.SetAddressBookPolicy
+ PSComputerName : outlook.office365.com
I've tried converting it to a string (with -join ',') and have tried casting it, but I can't get further then an error (which then is of another kind).
If I copy the output and then type it into the command, it works. So that part is correct. However, I would like to automate this.
Does anyone know how I can correctly provide an input into the below cmdlet and have it running as expected?
EDIT: added full script below:
$AddressLists = #()
$AddressLists = (Get-AddressList).Id | ? {$_ -like "*Company_1*"}
$AddressLists = $AddressLists -join ',' #Adding this line just results in another error...
Set-AddressBookPolicy -Identity "Company1" -AddressLists $AddressLists `
-RoomList "C1_Rooms" -GlobalAddressList "C1_GAL" -OfflineAddressBook "C1_OAB"
The result of $AddressLists is an array (System.Array) with contents:
\Company_1
\Company_1Country1
\Company_1Country2
\Company_1Department1
\Company_1Department2
If your variable produces what you are saying...
$AddressLists = (Get-AddressList).Id | {$_ -like "*Company_1*"}
\Company_1_Users,
\Company_1_Contacts,
\Company_1_DLs
Then In Theory When You Add It Into a ForEach Loop It Should Work Accordingly. I Don't Have Exchange To Test It (by removing $updatecommand and leaving the execution command :o)
Change the settings of an address book policy in Exchange Online
<https://learn.microsoft.com/en-us/exchange/address-books/address-book-policies/change-the-settings-of-an-address-book-policy>
$AddressLists = ("\Company_1_Users", "\Company_1_Contacts", "\Company_1_DLs")
$iD = "Company1"
$rL = "C1_Rooms"
$gAL = "C1_GAL"
$oAB = "C1_OAB"
ForEach($AddressList in $AddressLists){
Write-Host "Without an Exchange Server, I'm Just Demonstating The Update Process"
Write-Host "The AddressList Being Updated Is -- $AddressList"
$updatecommand = "Set-AddressBookPolicy -Identity $iD -AddressLists $AddressList -RoomList $rL -GlobalAddressList $gAL -OfflineAddressBook $oAB"
Write-Host $updatecommand
}
I am trying to test if a DNS zone exists in Powershell using the following cmdlet:
Get-DNSServerZone abc.com
That works great, but what I need to do now is turn that into a True/False evaluation depending on if there was an error or if there was data returned.
For example, this is a TRUE scenario:
$a = Get-DnsServerZone abc.com
$a
ZoneName ZoneType IsAutoCreated IsDsIntegrated IsReverseLookupZone IsSigned
-------- -------- ------------- -------------- ------------------- --------
abc.com Secondary False False False
Whereas this is a FALSE scenario:
$a = Get-DnsServerZone def.com
Get-DnsServerZone : The zone def.com was not found on server DNSSERVER1.
At line:1 char:6
+ $a = Get-DnsServerZone def.com
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (def.com:root/Microsoft/...S_DnsServerZone) [Get-DnsServerZone], CimException
+ FullyQualifiedErrorId : WIN32 9601,Get-DnsServerZone
What I'm struggling with is how to evaluate on that? In layman's terms I need to check if $a has actual data or not.
Many thanks!
what I need to do now is turn that into a True/False evaluation depending on if there was an error or if there was data returned.
If you can simply ignore failures and don't need the object returned by Get-DNSServerZone, you can do the following:
$zoneExist = [bool] (Get-DNSServerZone abc.com -ErrorAction Ignore)
-ErrorAction Ignore quietly ignores any (non-terminating) errors.
Passing Ignore to the common -ErrorAction parameter) simply discards the error, whereas SilentlyContinue, while also not outputting an error, still records it in the automatic $Error collection, allowing later inspection.
You could also complement -ErrorAction SilentlyContinue with something like
-ErrorVariable err, which would additionally record the command-specific errors in self-chosen variable $err, via the common -ErrorVariable parameter.
Cast [bool] maps Get-DNSServerZone's output to $true (an object describing the zone was output) or $false (nothing was output (to the success output stream), because an error occurred), taking advantage of PowerShell's implicit to-Boolean conversion.
If you want the zone-description object too:
$zoneExist = [bool] ($zoneInfo = Get-DNSServerZone abc.com -ErrorAction Ignore)
An alternative is to capture the zone-information first, and to query the automatic $? variable afterwards, which contains a Boolean value ($true or $false) that indicates whether the most recently executed statement caused any errors (whether suppressed or not).
$zoneInfo = Get-DNSServerZone abc.com -ErrorAction Ignore
$zoneExist = $?
You could wrap it in a try..catch:
try {
Get-DNSServerZone abc.com -ErrorAction Stop
}
catch {
Write-Warning "zone abc.com doesn't exist"
}
Or go the other way and ignore errors:
$a = Get-DNSServerZone abc.com -ErrorAction SilentlyContinue
if (!$a) {
Write-Warning "abc.com doesn't exist"
}
I am trying to set up a master CSV file that gets checked when a PowerShell script runs during an MDT task sequence. What the script is trying to do is take the mac address of the physically connected nic card and compare it to the CSV files to see if it matches the Mac address that is saved in the file. If the mac address matches the value in the CSV it renames the computer to value that is paired with the Mac Address. If there is no match rename it based on the computer serial number.
Here is the what I have some far.
$computer = Get-WmiObject Win32_ComputerSystem -ComputerName $oldname
#$Machost is Mac Address of the active Network Card
$MacHost=Get-NetAdapter -Name "Ethernet" | Select Macaddress
$ConvertMacHost= $MacHost[0] -replace '(:|-|\.)'
Write-Host "You mac address is: " $MacHost
#MacHost gets reformatted to take out Semicolons - Ex 0011223344AA
#MacLab is a variable that stores the Computer name and Mac Address from File created in Deep Freeze that matches Mac Address of host.
#MacLab is formated to make all Alpha in Mac Address Capitalized
$MacLab=Import-Csv 'C:/projectcsv/LH_office.csv' | Select Workstations,#{Label ="Mac Address"; Expression ={$_."Mac Address".ToUpper()}}|where-object {$_."Mac Address" -eq $ConvertMacHost}|Select Workstations
#Checks to see if Host Mac Address Matches CSV File
If ([string]::IsNullorEmpty($MacLab))
{
Write-Warning -Message "No Mac Address found in our Records that Match the Host Machine Mac Address: Exit code 11001"
write-host ""
exit 11001
}Else{
$strUser = "******\domainadd"
$strDomain = "******"
$strPassword = ConvertTo-SecureString "*******" -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PsCredential $strUser,
$strPassword
#---- Define Prefix to be used -----#
$strPrefix='LH'
$strEnding='DESK'
#----- Get Serial Number ------#
$SN=(gwmi win32_BIOS).serialnumber
#--If working with VM, the SN length is longer than 15 Char------#
if($SN.length -gt 11) {
#Get the last 7 Char of Serial
$StrName=($SN.substring($SN.length - 11)) -replace "-",""
$strComputerName=$strPrefix+"-"+$StrName+"-"+$strEnding
} else {$strComputerName=$strPrefix+"-"+$SN+"-"+$strEnding
}
#------ Rename the Computer using WMI --------#
#$computer=gwmi win32_computersystem
#$computer.rename($strComputerName)
#-----Powershell 5 above use-------#
rename-computer -NewName $StrComputerName -PassThru -DomainCredential $Credentials
When I run the code I get this error message:
I added the computer I was working to the csv and still get the error. I know later I have to add the function where it checks to see if the name is already in AD. but want to get it working first. Please any help you can give would be helpful.
Edit: Here is a picture of the CSV file that shows what information is in there.
After making the corrections suggested I get these errors when the scripts run.
At \\LH-WDS-MDT\DeploymentShare$\Scripts\CSV_Computer_Rename_LH.ps1:7 char:13
+ $DriveMap = New-PSDrive -Name "M" -Root "\\LH-WDS-MDT\CSV_Files" -PSP ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TaskSequencePSHost 7/13/2020 2:24:53 PM 0 (0x0000)
InvalidOperation: (M:PSDriveInfo) [New-PSDrive], Win32Exception TaskSequencePSHost 7/13/2020 2:24:54 PM 0 (0x0000)
Exception calling "Substring" with "1" argument(s): "StartIndex cannot be less than zero.
Parameter name: startIndex" TaskSequencePSHost 7/13/2020 2:24:55 PM 0 (0x0000)
At \\LH-WDS-MDT\DeploymentShare$\Scripts\CSV_Computer_Rename_LH.ps1:12 char:1
+ $CompNameSerial = ($CompSerialNumber.substring($CompSerialNumber.leng ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TaskSequencePSHost 7/13/2020 2:24:55 PM 0 (0x0000)
NotSpecified: (:) [], MethodInvocationException TaskSequencePSHost 7/13/2020 2:24:55 PM 0 (0x0000)
Skip computer 'ADMINIS-8EMV500' with new name '#{Workstations=LH-TestMo-5040}' because the new name is not valid. The new computer name entered is not properly formatted. Standard names may contain letters (a-z, A-Z), numbers (0-9), and hyphens (-), but no spaces or periods (.). The name may not consist entirely of digits, and may not be longer than 63 characters. TaskSequencePSHost 7/13/2020 2:25:03 PM 0 (0x0000)
At \\LH-WDS-MDT\DeploymentShare$\Scripts\CSV_Computer_Rename_LH.ps1:29 char:5
+ rename-computer -NewName $NameComputerCSV -PassThru -DomainCreden ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TaskSequencePSHost 7/13/2020 2:25:03 PM 0 (0x0000)
InvalidArgument: (#{Workstations=LH-TestMo-5040}:String) [Rename-Computer], InvalidOperationException TaskSequencePSHost 7/13/2020 2:25:03 PM 0 (0x0000)
$MacHost is receiving an object with properties, so you need to specify the property you want or you get weird results, which is causing Where-Object to fail.
Specifically, $ConvertMacHost ended up being something like #{MacAddress=9CB6D0959AE5}
This line
$ConvertMacHost= $MacHost[0] -replace '(:|-|\.)'
should be
$ConvertMacHost= $MacHost[0].MacAddress -replace '(:|-|\.)'
I'm writing a script where in one part I want to export some settings of the SCVMM VM and set it in another. I have to run it from another machine, which doesn't have SCVMM installed so I have to call our VMM with Invoke-Command.
Unfortunately, variables I'm using in the code behave unexpectedly (don't want to say wrong, I assume it's by design). When they are used in parameter they don't transfer whole object that's in them, but just the Name.
$vm01 = Get-VM -Name VM01
$vm02 = Get-VM -Name VM02
$vm01name =$vm01.Name
$vm02name =$vm02.Name
$VMMparam = Invoke-Command –Computername VMM01 –ScriptBlock {
$VMMvm01=Get-SCVirtualMachine -VMMServer "VMM01.pandora.corp" -Name $using:vm01name
$vmcloud = $VMMvm01.Cloud
$vmos = $VMMvm01.OperatingSystem
$vmuserrole = $VMMvm01.UserRole
$vmowner = $VMMvm01.Owner
return $vmcloud,$vmos,$vmuserrole,$vmowner
}
$VMMcloud = $VMMparam[0]
$VMMos = $VMMparam[1]
$VMMuserrole = $VMMparam[2]
$VMMowner = $VMMparam[3]
Invoke-Command -ComputerName VMM01 -ScriptBlock {
if ($using:VMMcloud -eq $null){
Set-SCVirtualMachine -vm $using:vm02name -OperatingSystem $using:VMMos.Name
}
else{
Set-SCVirtualMachine -vm $using:vm02name -Cloud $using:VMMcloud -OperatingSystem $using:VMMos.Name -UserRole $using:VMMuserrole -Owner $using:VMMowner
}
}
This runs well until it's supposed to enter the Cloud object into the -cloud parameter. It ends in error:
Cannot bind parameter 'Cloud'. Cannot convert the "CLOUD01" value of type "Deserialized.Microsoft.SystemCenter.VirtualMachineManager.Cloud" to type "Microsoft.SystemCenter.VirtualMachineManager.Cloud".
+ CategoryInfo : InvalidArgument: (:) [Set-SCVirtualMachine], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.SetV
MCmdlet
+ PSComputerName : VMM01
If I call just the $using:VMMcloud variable inside of the Invoke-Command, it returns correctly. But when it's in parameter, just the Name value is returned. I tried it with arguments instead of prefixed variables, but same output.
Can you help me?
P.S. This is my first question in here. Hope the formatting is right and the problem described understandably. If not, ask away.