I am trying to create a PowerShell script that will find an available drive letter, map a network drive, and then change to that mapped drive. I found the following which mapped \\server\share as the D: drive:
$Drive = New-PSDrive -Name $(for($j=67;gdr($d=[char]$J++)2>0){}$d) -PSProvider FileSystem -Root \\server\share\
I can manually enter D:, but how can I change this in a script? I was thinking along the lines of this:
$Drive = $Drive.Trim(":")
But the statement above throws the following error:
Method invocation failed because [System.Management.Automation.PSDriveInfo] does
not contain a method named 'Trim'.
At line:1 char:1
+ $Drive = $Drive.Trim(":")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
You could check a list of potential drive letters against the list of currently assigned drive letters and use the first unused one:
$used = Get-PSDrive | Select-Object -Expand Name |
Where-Object { $_.Length -eq 1 }
$drive = 90..65 | ForEach-Object { [string][char]$_ } |
Where-Object { $used -notcontains $_ } |
Select-Object -First 1
New-PSDrive -Name $drive -PSProvider FileSystem -Root \\server\share
Set-Location "${drive}:"
or a random one from that list:
$used = Get-PSDrive | Select-Object -Expand Name |
Where-Object { $_.Length -eq 1 }
$unused = 90..65 | ForEach-Object { [string][char]$_ } |
Where-Object { $used -notcontains $_ }
$drive = $unused[(Get-Random -Minimum 0 -Maximum $unused.Count)]
New-PSDrive -Name $drive -PSProvider FileSystem -Root \\server\share
Set-Location "${drive}:"
The functions used in Ansgar's answer are likely returning the DVD/CD drive because it has no media in it. To get a free drive letter, that is likely* not the CD/DVD drive we search from i-z:
$dl=ls function:[i-z]: -n | ?{ !(test-path $_) } |select -last 1
Related
I need to count files inside given folders
example:
Folder A
Folder B
Folder C
For each folder I need to count how many files there are, and at the end sum the total.
What is the best to way to do this?
try this :
$DirList=#('C:\temp\BATCHHISTOCRE', 'C:\temp\tmp', 'C:\temp\444')
$DirList | %{
[pscustomobject]#{
Dirname=$_
NbFile=(Get-ChildItem -Path $_ -File).Count # Add -recurse if you want all tree into your dir
}
}
Tagging on to #Esperento57:, helpful answer.
Yeppers, it does work, but it will also error off if the folder path has no files; whereas using Measure-Object in the mix, can address that.
$DirList = #('D:\Temp\AddressFiles',
'D:\Temp\BonoboGitServer',
'D:\Temp\Book'
)
$DirList |
ForEach-Object {
[pscustomobject]#{
Dirname = $PSItem
NbFile = (Get-ChildItem -Path $PSItem -File).Count
}
}
# Results
<#
Dirname NbFile
------- ------
D:\Temp\AddressFiles 3
The property 'Count' cannot be found on this object. Verify that the property exists.
At line:8 char:5
+ [pscustomobject]#{
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], PropertyNotFoundException
+ FullyQualifiedErrorId : PropertyNotFoundStrict
D:\Temp\Book 4
#>
Whereas using the Measure-Object cmdlet, addresses the issue...
$DirList = #('D:\Temp\AddressFiles',
'D:\Temp\BonoboGitServer',
'D:\Temp\Book'
)
$DirList |
ForEach-Object {
[pscustomobject]#{
Dirname = $PSItem
NbFile = (Get-ChildItem -Path $PSItem -File |
Measure-Object).Count
}
}
# Results
<#
Dirname NbFile
------- ------
D:\Temp\AddressFiles 3
D:\Temp\BonoboGitServer 0
D:\Temp\Book 4
#>
I am trying to check ACLs on UNC paths via the Get-Acl cmdlet.
The below works fine when browsing the local filesystem or on a UNC path without spaces.
$ou = 'OU=Security Groups,DC=mydomain,DC=local'
$basepath = '\\mydomain\dfsroot'
$filter = '*501*'
Get-ADGroup -SearchBase $ou -Filter { Name -like $filter } | % {
$principle = $_.samAccountName
Get-ChildItem -LiteralPath $basepath -Recurse | % {
$path = $_.FullName
($path | Get-Acl).Access.IdentityReference | % { if ( $_.Value -match $principle ) { Write-Host "$principle has rights to $path" }}
}
}
On UNC paths with spaces I get a "FileNotFoundException":
Get-Acl : \local501\dfsroot\docs\Accounting\Bankruptcy Files\NOTICE TO MEMBERSHIP RE-CHAPTER 11.pdf
At C:\Users\administrator.LOCAL501\Documents\IT Support Guys - (855) 4 IT GUYS\Files\find_paths_by_principle.ps1:11 char:18
+ ($path | Get-Acl).Access.IdentityReference | % { if ( $_.Valu ...
+ ~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Acl],FileNotFoundException
+ FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.GetAclCommand
Can somebody help me understand what's going on here?
Thanks!
Ignore this!
My DFS share is full of corruption!
Filenames just happened to be ones with spaces.
Good news!
So your code is a little needlessly complicated. Here's a script that's easier to understand the flow and shouldn't error out on spaces:
If (-not (Test-Path -Path DFS:\))
{ New-PSDrive -Name DFS -PSProvider FileSystem -Root \\mydomain\dfsroot }
$OU = 'OU=Security Groups,DC=mydomain,DC=local'
$Filter = '*501*'
$Principles = (Get-ADGroup -SearchBase $OU -Filter {Name -like $Filter}).samAccountName
$Collection = #()
ForEach ($Path in (Get-ChildItem -Path DFS:\ -Recurse -ErrorVariable +CustomERR))
{
## Using an array literal so items don't end up appended to one giant hashtable
$Collection += #(
#{ Path = $Path.FullName
Acl = (Get-Acl -Path $Path.FullName).Access.IdentityReference.Value
}
)
}
ForEach ($Principle in $Principles)
{
ForEach ($Item in $Collection)
{
If ($Item.Acl -contains $Principle)
{
Write-Host "'$Principle' has rights to '$($Item.Path)'"
}
}
}
Edit: made some optimizations
After trying a number of approaches, including what seemed an excellent suggestion at http://www.bdevuyst.com/powershell-path-msbuild-exe/, which gave me an error, I tried to break it down. Though I get the latest MSBuild registry key (14.0), I still get this error when I try to extract the path to MSBuild:
Get-ItemProperty : Cannot find path 'C:\USERS\user\Desktop\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSBuild\ToolsVersions\14.0' because it does not exist.
At C:\USERS\mtroi\Desktop\VSS_POC1_Setup.ps1:529 char:5
+ Get-ItemProperty -Path $MsBuildVersion -Name MSBuildToolsPath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\USERS\mtroi\...lsVersions\14.0:String) [Get-ItemProperty], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand
# 32bit or 64bit local OS?
if($ENV:PROCESSOR_ARCHITECTURE -eq "x86")
{$HKLMpath = "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\"}
elseif($ENV:PROCESSOR_ARCHITECTURE -eq "AMD64")
{$HKLMpath = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\MSBuild\ToolsVersions\"}
else
{Write-Host "Local processor architecture not supported. Exiting installation..."; EXIT}
# Which path (version) of local MSBuild?
$_decSep = [System.Threading.Thread]::CurrentThread.CurrentUICulture.NumberFormat.CurrencyDecimalSeparator;
$MsBuild1 = #(Get-ChildItem -Path $HKLMpath | Where { $_.Name -match '\\\d+.\d+$' })
ForEach ($build in $MsBuild1)
{
$Expression=$Expression+","+[System.Convert]::ToDecimal($build.Name.Substring($build.Name.LastIndexOf("\") + 1))
}
$MsBuildVersion = Get-ChildItem -Path $HKLMpath | Where { $_.Name -match '\\\d+.\d+$' } |
Sort-Object -Property #{Expression=$Expression} -Descending |
Select-Object -First 1 #| Get-ItemProperty -Name MSBuildToolsPath
Get-ItemProperty -Path $MsBuildVersion -Name MSBuildToolsPath
I try execute .exe file which was copied from network folder to host folder with keys for silent installation by using this script:
Get-ChildItem "D:\" -Filter *.exe | Where Name -NotMatch '.*NoDB\.exe$' | % {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort No -Descending | Select -ExpandProperty Name -First 1 | Invoke-Item -s2 -sp"-SilentInstallation=standalone -UpdateMaterials=yestoall -UpgradeDBIfRequired=yes"
But I receive error:
Invoke-Item : A parameter cannot be found that matches parameter name 's2'.
At line:20 char:78
+ ... ding | Select -ExpandProperty Name -First 1 | Invoke-Item -s2 -sp"-Si ...
+ ~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Item], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.InvokeItemCommand
You get the error because you pass the parameters to the Invoke-Item cmdlet and not to your application,
Try to invoke your executeable with & and pass the parameters:
Get-ChildItem "D:\" -Filter *.exe | Where Name -NotMatch '.*NoDB\.exe$' | % {
New-Object psobject -Property #{
No = [int]([regex]::Match($_.Name, '(?<=CL)\d+').Value)
Name = $_.FullName
}
} | Sort No -Descending | Select -ExpandProperty Name -First 1 |
Foreach { & $_ -s2 -sp"-SilentInstallation=standalone -UpdateMaterials=yestoall -UpgradeDBIfRequired=yes"}
I have an arraylist of all folders and files where I want to get the ACL off.
Everything runs well in my Foreach loop.
But for one odd reason it throws:
Get-Acl : Illegal characters
+ CategoryInfo : NotSpecified: (:) [Get-Acl], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.GetAclCommand
When I run the get-acl manual with the 'faulty' path, I get the ACL.
My code is:
$ACL = get-acl -LiteralPath "$Path" | select -ExpandProperty access | select IdentityReference
$Result = Compare-Object -ReferenceObject $ACLListAccess -DifferenceObject $ACL -Property Access -PassThru
if ($Result.count -ne 0)
{
$ExplicitTest = get-acl -LiteralPath "$Path" | select -ExpandProperty access
if ($ExplicitTest.IsInherited.count -ne $ACLListAccessFull.count -and $ExplicitTest.IsInherited -Like "*False*")
{
$WrongFolders.Add($Path) | Out-Null
}
}
The Path with the 'illegal character' is
\mycompany.com\folders\Algemeen\Reme§ysen
Sorry, cannot repro your problem and comment does not allow me to paste this
D:\temp\a> get-acl .\aaa§bbb
Directory: D:\temp\a
Path Owner Access
---- ----- ------
aaa§bbb adil BUILTIN\Administrators Allow FullControl...
if you copy paste that character, do you also get 167?
C:\> [int][char]'§'
167