I want throw an error if I call the function with a TypeAdressage not equal to "Dynamique" or "Statique" but it throw the error when i call it with "Dynamique"
function Changer-Type {
param(
[string]$Identifiant,
[string]$TypeAdressage,
[string]$Path
)
if ($TypeAdressage -ne "Dynamique"-or ($TypeAdressage -ne "Statique")){
Write-Error "Type Adressage impossible"
}
else{
if(-not(Test-Path $Path -PathType Leaf) -or [IO.Path]::GetExtension($Path) -ne '.csv') {
throw 'File does not exist or is not a Csv...'
}
$computers = Import-Csv -Path $Path -Delimiter ';'
$computers | Where-Object { $_.Identifiant -eq $Identifiant } |
ForEach-Object { $_.TypeAdressage = $TypeAdressage }
# write the updated $computers object array back to disk
$computers | Export-Csv -Path $Path -Delimiter ';' -NoTypeInformation
}
}
$csvPath = 'C:\Temp\Peripherique.csv'
Changer-Type -Identifiant "Q00032" -TypeAdressage "Dynamique" -Path $csvPath
Changer-Type -Identifiant "PWIN10" -TypeAdressage "test" -Path $csvPath
Why not let PowerShell validate the parameter $TypeAdressage to always be one of the two (or more) predefined strings?
function Changer-Type {
param(
[string]$Identifiant,
[ValidateSet('Dynamique','Statique')]
[string]$TypeAdressage,
[string]$Path
)
if(-not(Test-Path $Path -PathType Leaf) -or [IO.Path]::GetExtension($Path) -ne '.csv') {
throw 'File does not exist or is not a Csv...'
}
$computers = Import-Csv -Path $Path -Delimiter ';'
$computers | Where-Object { $_.Identifiant -eq $Identifiant } |
ForEach-Object { $_.TypeAdressage = $TypeAdressage }
write the updated $computers object array back to disk
$computers | Export-Csv -Path $Path -Delimiter ';' -NoTypeInformation
}
Changer-Type -TypeAdressage Dynamique
As extra bonus, using [ValidateSet()] will also give you intellisense when coding:
I suggest changing your if statement. Because you are saying:
if
$TypeAdressage not equal to "Dynamique"
or
$TypeAdressage not equal to "Dynamique".
That if statement will always be true, because $TypeAdressage will never be both "Dynamique" and "Dynamique".
Related
I am trying to recursively find references of Constants.cs of an any other .cs files in a directory containing files with Paths. Name of the files are stored procedures and they have the references(Paths) for that stored procedure.
This is PowerShell Script that i have written.
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)]
[string]$ProceduresFile,
[Parameter(Position=1, Mandatory=$true)]
[string]$ReferencesDir,
[Parameter(Position=2, Mandatory=$true)]
[string]$Project,
[Parameter(Position=3, Mandatory=$false)]
[string]$OutputPath = "."
)
$ErrorActionPreference = "Stop"
$storedProcFromFile = [IO.File]::ReadAllLines($ProceduresFile)
function Search-PSfile
{
param(
[string] $ReferencesDir,
[string] $Project,
[string] $file
)
$procedureName = $file.Split(".")[0].ToLower()
$textName = "${procedureName}.txt"
$pattern = "\b${Project}\.\b"
#check for Constant.cs files in project directory-- returs true if present
$isConstantFile = [bool](Get-ChildItem -Path $ReferencesDir -Filter $textName -Recurse |
Get-Content |
Select-String -Pattern "\bConstants.cs\b" |
Select-String -Pattern $pattern -Quiet)
#check for .cs files in project directory besides Constants.cs .. returs true if present
$isOtherCsFile = [bool](Get-ChildItem -Path $ReferencesDir -Filter $textName -Recurse |
Get-Content |
Select-String -Pattern "\b.cs\b" |
Select-String -Pattern "\bConstants.cs\b" -NotMatch |
Select-String -Pattern $pattern -Quiet)
$filePattern = "\b${procedureName}\b"
#check for .sql files other than itself.. returs true if present
$isUsedSql = [bool](Get-ChildItem -Path $ReferencesDir -Filter $textName -Recurse |
Get-Content |
Select-String -Pattern "\.sql" |
Select-String -Pattern $filePattern -NotMatch -Quiet)
# if there are no constant files and no .sql file and no there .cs files then SP is not used
If(!$isConstantFile -and !$isUsedSql -and !$isOtherCsFile)
{
return $false
}
# If there are Constants.cs then write SP name in Used.txt end function
Elseif ($isConstantFile)
{
return $true
}
# If there are other .cs files then check if SP is commented out if yes then 'not used' else 'used'
Elseif ($isOtherCsFile)
{
Get-ChildItem -Path $ReferencesDir -Filter $textName -Recurse |
Get-Content |
Select-String -Pattern "\b.cs\b" |
Select-String -Pattern "\bConstants.cs\b" -NotMatch |
Select-String -Pattern $pattern |
ForEach-Object{
$isUnCommented = [bool](Get-Content |
Select-String -Pattern $filePattern |
Select-String -Pattern "\/\/" -NotMatch -Quiet)
if($isUnCommented)
{
return $true
}
else
{
return $false
}
}
}
# if there are no .cs files only .sql files then do a recusion and check for that .sql file
Elseif ($isUsedSql)
{
Get-ChildItem -Path $ReferencesDir -Filter $textName -Recurse |
Get-Content |
Select-String -Pattern "\.sql" |
Select-String -Pattern $filePattern -NotMatch |
ForEach-Object{
$sqlFile = (Get-Item $_).Name
Search-PSfile -ReferencesDir $ReferencesDir -Project $Project -file $sqlFile -OutputPath $OutputPath
}
}
}
function Write-PSfile
{
param(
[string]$OutputPath,
[string]$File,
[string]$FileName,
[string]$Text
)
$fileExist = Test-Path "${OutputPath}\${FileName}"
if(!$fileExist)
{
$line = "${File} | ${Text}"
New-Item -Path $OutputPath -Name $FileName -ItemType "file" -Value $line
}
else {
$line = "${File} | ${Text}"
$path = "${OutputPath}\${FileName}"
Add-Content -Path $path -Value $line
}
}
$storedProcFromFile | ForEach-Object{
$isUsed = Search-PSfile -ReferencesDir $ReferencesDir -Project $Project -file $_ -OutputPath $OutputPath
if($isUsed)
{
Write-PSfile -OutputPath $OutputPath -File $_ -FileName "Used.txt" -Text "Used"
}
else
{
Write-PSfile -OutputPath $OutputPath -File $_ -FileName "NotUsed.txt" -Text "Not Used"
}
}
Write-Host "Script Ran Successfully"
I am not sure why I am getting cmdlet Get-Content at command pipeline position 1 for second elseif Elseif ($isOtherCsFile)statement but others are working fine. Any Suggestion is welcome. Thankyou.
The purpose of this code is to transfer files from one location to another and to log whether the transfer was a success or a failure.
Everything works except I am having issues with the log. I want the log to be in CSV format and there to be 3 columns: success/failure, from location, and to location. This is outputting the results all into rows with one column.
I've tried the Export-Csv option but that looks for objects/properties so only displays the length(I have strings too). Add-content works but there is only one column. Any suggestions?
#LOCATION OF CSV
$csv = Import-Csv C:\test2.csv
#SPECIFY DATE (EXAMPLE-DELETE FILES > 7 YEARS. 7 YEARS=2555 DAYS SO YOU WOULD ENTER "-2555" BELOW)
$Daysback = "-1"
#FILE DESTINATION
$storagedestination = "C:\Users\mark\Documents\Test2"
#LOG LOCATION
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
foreach ($line in $csv) {
$Path = $line | Select-Object -ExpandProperty FullName
$DatetoDelete = $CurrentDate.AddDays($DaysBack)
$objects = Get-ChildItem $Path -Recurse | Select-Object FullName, CreationTime, LastWriteTime, LastAccessTime | Where-Object { $_.LastWriteTime -lt $DatetoDelete }
foreach ($object in $objects) {
try
{
$sourceRoot = $object | Select-Object -ExpandProperty FullName
Copy-Item -Path $sourceRoot -Recurse -Destination $storagedestination
Remove-Item -Path $sourceRoot -Force -Recurse
$temp = $s, $sourceRoot, $storagedestination
$temp | add-content $loglocation
}
catch
{
$temp2 = $f, $sourceRoot, $storagedestination
$temp2 | add-content $loglocation
}
}
}
All your | Select-Object -ExpandProperty are superfluous, simply attach the property name to the variable name => $Path = $line.FullName
Why calculate $DatetoDelete inside the foreach every time?
Output the success/fail to a [PSCustomObject] and gather them in a variable assigned directly to the foreach.
Untested:
$csv = Import-Csv C:\test2.csv
$Daysback = "-1"
$destination = "C:\Users\mark\Documents\Test2"
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.Date.AddDays($DaysBack)
$Log = foreach ($line in $csv) {
$objects = Get-ChildItem $line.FullName -Rec |
Where-Object LastWriteTime -lt $DatetoDelete
foreach ($object in $objects) {
$Result = $s
$sourceRoot = $object.FullName
try {
Copy-Item -Path $sourceRoot -Recurse -Destination $destination
Remove-Item -Path $sourceRoot -Recurse -Force
} catch {
$Result = $f
}
[PSCustomObject]#{
'Success/Fail' = $Result
Source = $sourceRoot
Destination = $destination
}
}
}
$Log | Export-Csv $loglocation -NoTypeInformation
I am writing an application that looks through a directory tree and reports if a folder is inactive based on last write time and read only attribute.
However my loop stops after like 7 iterations even though there are thousands of folders.
My code looks like:
function FolderInactive{
Param([string]$Path)
$date = (Get-Date).AddDays(-365)
$anyReadOnly = $false
Get-ChildItem $Path -File -ErrorAction SilentlyContinue | ForEach-Object {
if($_.LastWriteTime -ge $date){
$false
continue
}
if($_.IsReadOnly -eq $false){
$anyReadOnly = $true
}
}
$anyReadOnly
}
Get-ChildItem "some drive" -Recurse | where {$_.PSIsContainer} | Foreach-Object {
Write-Host $_.FullName
FolderInactive($_.FullName)
}
If I comment out the FolderInactive function call in the Foreach loop it prints all the folders, but with the function call it stops after a few iterations. What is happening?
You cannot use continue with the Foreach-Object cmdlet. Foreach-Object is a cmdlet, not a loop. You instead want to use the loop:
function FolderInactive{
Param([string]$Path)
$date = (Get-Date).AddDays(-365)
$anyReadOnly = $false
$items = Get-ChildItem $Path -File -ErrorAction SilentlyContinue
foreach($item in $items)
{
if($item.LastWriteTime -ge $date){
$false
continue
}
if($item.IsReadOnly -eq $false){
$anyReadOnly = $true
}
}
$anyReadOnly
}
This also can be simplified:
function FolderInactive
{
Param([string]$Path)
$date = (Get-Date).AddYears(-1)
$null -ne (Get-ChildItem $Path -File -ErrorAction SilentlyContinue |
Where {$_.LastWriteTime -ge $date -and $_.IsReadOnly})
}
I need create this list to allow an other program to properly work. I use this code:
function analyse {
Param(
[parameter(Mandatory=$true)]
[String]$newPath
)
cd $newPath
dir | Foreach-Object {
$data = Get-Content -Path o:\******\public\ParcoursArborescence\Limitless\data.txt
if ($_.PsisContainer -eq $True) {
$testPath = $_.FullName + ";"
$name = $testPath
$testPath = $data -match [regex]::escape($testPath)
$testpath
if($testPath.Length -eq 0) {
$name | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\data.txt"
if ($_.FullName.Length -gt 248) {
"ecriture"
$result += $_.FullName + "`r"
} else {
"nouvelle analyse"
$_.Fullname
analyse $_.FullName
}
}
} else {
$testPath = $_.Directory.FullName + ";"
$name = $testPath
$testPath = $data -match [regex]::escape($testPath)
if($testPath.Length -eq 0) {
$name | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\data.txt"
$_.FullName.Length
if ($_.FullName.Length -gt 260) {
"ecriture2"
$result += $_.Directory.Name + "`r"
}
}
}
}
$result | Out-File -Append "o:\******\public\ParcoursArborescence\Limitless\bilanLimitless.txt"
}
But it takes hours and hours... I need to use this in thousands of folders. So, do you have any idea about how could it get faster ?
Maybe I'm oversimplifying things here, but why not list all the files at once, and test their FullName Length (PS 3.0 needed for the -File parameter of Get-ChildItem) ?
$maxLength = 248
Get-ChildItem $newPath -Recurse |
Where-Object { ($_.FullName.Length -gt $maxLength) } |
Select-Object -ExpandProperty DirectoryName -Unique |
Out-File "overlength_paths.txt"
For PS 2.0:
$maxLength = 248
Get-ChildItem $newPath -Recurse -File |
Where-Object { ($_.FullName.Length -gt $maxLength) -and (-not $_.PSisContainer) } |
Select-Object -ExpandProperty DirectoryName -Unique |
Out-File "overlength_paths.txt"
I am using following coe to replace the string
$folders=Get-ChildItem -Path "C:\temp\Database Scripts"
foreach($folder in $folders)
{
Write-Host $folder
$spath=[string]::Concat("C:\temp\Database Scripts\", $folder)
$subfolders=Get-ChildItem $spath
foreach($subfolder in $subfolders )
{
if($subfolder -match "Running Scripts")
{
$subfolerpath=[string]::Concat($spath,"\",$subfolder,"\*")
$files =get-childitem -Path $subfolerpath -include "AVEVAScripts*"
if($files -ne $null)
{
foreach( $file in $files)
{
Write-Host $file;
(Get-Content $file) | ForEach-Object {$_ -replace "DATABASE_USER","fhghjgj" `
-replace "DATABASE_PASSWORD", "DFGHFHJGJH" } |Set-Content $file
}
}
}
}
}
But ending up with following error.
Set-Content : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
Please help :)
Remove the $x in the end of Set-Content. $x is never declared.
Also, you could simplify it a lot. Ex:
Get-ChildItem -Filter "Running Scripts" -Path "C:\temp\Database Scripts" -Recurse | ForEach-Object {
Get-ChildItem -Path $_.FullName -Filter "AVEVAScripts*" -Recurse | ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}
}
Or find all files that includes "AVEVAScripts" in it's name, then check if their full path includes "Running Scripts"
Get-ChildItem -Filter "AVEVAScripts*" -Path "C:\temp\Database Scripts" -Recurse |
Where-Object { $_.FullName -like "*Running Scripts*" } |
ForEach-Object {
(Get-Content $_.FullName) | ForEach-Object {
$_ -replace "DATABASE_USER","fhghjgj" -replace "DATABASE_PASSWORD", "DFGHFHJGJH"
} | Set-Content $_.FullName
}