none
Copy-Item et backup RRS feed

  • Question

  • Bonjour,

    Cela fait plusieurs jours que je tente d'écrire un script pour sauvegarder les logs de mes serveurs (je précise que je suis novice en programmation) je commence à toucher au but mais je butte sur un problème...

    L'idée générale du script est d'utiliser un fichier .ini pour gérer les paramètres (comme la liste des serveurs à sauvegarder ou encore le chemin vers le dossier de backup) afin d'assurer une meilleur portabilité dudit script, ensuite j’exécute une série de teste et travaux préparatoire (test de connexion avec les serveurs, vérification de présence du dossier de backup etc.) puis enfin vient la sauvegarde à proprement parlé (dont vous trouverez le code ci-dessous) :

    Function Backup-EventLogs
    {
        $Logs = $ListLogs.Split(",")
        Foreach($Server in $ServerList)
            {
                $Tmp = $TmpRaw.replace("<SERVEUR>", $Server)
                $BackupSubDir = $BackupDirPath+"\"+$Date+"_"+$Server
                Write-Host "  $Server"
                Foreach($Log in $Logs)
                    {
                        Try
                            {
                                $Path = "$tmp\$Log.evtx"
                                $BackupLog = Get-WmiObject -Class Win32_NTEventlogFile -ComputerName $Server | Where-Object LogfileName -eq $Log
                                $BackupLog.BackupEventlog($Path) | Out-Null
                                Copy-Item -Path $Path -Destination $BackupSubDir -Force
                                Write-Host "    $Log.evtx... OK"
                            }
                         Catch
                            {
                                $_.exception.message
                            }
                    } #End Foreach Logs
            } #End Foreach Serveurs
    } #End Backup-EventLogs

    la variable $TmpRaw contient une string du genre \\<SERVEUR>\c$\tmp qui est extraite du fichier ini. Il s'agit en fait du chemin vers un dossier temporaire nécessaire pour sauvegarder les logs avec la méthode .backupEventlog, car j'ai cru comprendre que cette dernière ne permettait pas de sauvegarder les logs sur un support distant.

    Une fois les logs sauvegardés, j’exécute une copie vers le dossier de sauvegarde définitif... oui, mais non ! la sauvegarde en local s'effectue bien mais pas la copie, plus bizarre encore la commande Copy-Item ne renvoi aucune erreur et lorsque je tape la commande manuellement en remplaçant les variable par leur valeur respective ça fonctionne !

    Quelqu'un peut-il m'expliquer ? (tant que je suis là je suis également preneur de toute remarque qui me permettrait d'améliorer mon script ou ma façon de l'écrire :-) )

    Merci d'avance, cordialement.

    lundi 8 juillet 2019 11:45

Réponses


  • Mon script s’exécute sur la machine A, se connecte sur B (THOT-AD1) avec Invoke d'où il lance la copie des log à destination de A ! Ça compte vraiment pour un double saut ? Même si la commande est à destination de la machine d'origine ?


    c'est un double même si la machine C est la A !! dommage

    a tu essayer la solution suivante :

    $ids = New-PSSession $server
    $Path = "c:\tmp\$Log.evtx"
    Copy-Item -FromSession $ids -Path $Path -Destination $BackupSubDir
    Remove-PSSession $ids

    • Marqué comme réponse Nóla lundi 15 juillet 2019 07:00
    samedi 13 juillet 2019 15:37

Toutes les réponses

  • salut Mira.pro

    ton script semble correct :)

    tu devrait commencer par vérifier le contenu de $BackupSubDir et de $BackupDirPath à l'execution dans la fonction

    Dans un deuxième temps comme ta fonction fait partie d'un script plus grand que l'on n'a pas, exécute tu cette fonction dans une session à distance ?

    si oui tu a sans doute un problème de double saut 

    si non je vois pas ou est l'erreur, le mieux alors est de faire du débogage pas à pas dans l’éditeur ISE pour voir l'état des variable et aussi de nous transmettre les messages d'erreurs si il y en a 


    • Modifié 6ratgus mardi 9 juillet 2019 16:33
    mardi 9 juillet 2019 16:33
  • Bonjour 6ratgus,

    Tout d'abord merci pour ta réponse :-)

    Ensuite, non la fonction ne s’exécute pas sur une session à distance, comme je le disais je suis relativement novice en Powershell et je ne suis pas très familier le système de fonctionnement des sessions distantes... par exemple je ne comprends pas la différence entre New-PsSession et Enter-PsSession (c'est embêtant ^^) en fait j'utilise simplement l'attribut -ComputerName quand j'ai besoin pour exécuter une commande sur une machine distante et le symbole "c$" pour désigner un chemin d’accès local (sur le lecteur C:\ du coup) du genre "\\<SERVEUR>\c$\tmp".

    Quand aux variables $BackupSubDir et $BackupDirPath leur contenu semble correcte, de même pour la variable $Path. Malgré cela, quand je lance le script rien ne ce passe, mais si je lance moi même la commande (en remplaçant les variables par les valeurs correspondante) la copie s'effectue ! En fait c'est comme si le script passait la commande sans l’exécuter...

    EDIT:

    C'est vraiment très bizarre, si j’insère dans le script la commande

    Copy-Item "\\THOT-AD\c$\tmp\*" -Destination "\\THOT-CLT\Backuplog\20191007_THOT-AD"
    Rien ne se passe, mais si je l'entre manuellement dans l'invite là ça fonctionne...

    • Modifié Nóla mercredi 10 juillet 2019 11:29
    mercredi 10 juillet 2019 11:08
  • Bonjour,

    Peut-être le c$ qui pose problème ?

    Essayez de créer un partage caché nommé tmp$ et modifiez \\thot-ad\c$\tmp par \\thot-ad\tmp$ 

    • Marqué comme réponse Nóla mercredi 10 juillet 2019 12:42
    • Non marqué comme réponse Nóla mercredi 10 juillet 2019 14:21
    mercredi 10 juillet 2019 12:10
  • bingo !

    Merci Spunamo, le problème semble effectivement venir du c$, j'ai partage le dossier tmp, remplacé le paramètre dans le script et c'est tout bon :-)

    Mais à présent... quelqu'un connaîtrait-il un moyen "techniquement abordable" de partager un dossier avec Powershell en sachant que je tourne sous W7/W2K8 ? J'ai cru comprendre que le module SmbShare n'était pas dispo sur les versions antérieurs à W10...


    EDIT:

    Bon OK j'me suis un peu emballé... ca marche pas en fait -_-'

    J'ai modifié le code

    $Path = "$tmp\$Log.evtx"
    $BackupLog = Get-WmiObject -Class Win32_NTEventlogFile -ComputerName $Server | Where-Object LogfileName -eq $Log
    $BackupLog.BackupEventlog($Path) | Out-Null
    Copy-Item -Path $Path -Destination $BackupSubDir -Force
    Write-Host "    $Log.evtx... OK"

    pour que la variable $tmp soit égale à \\THOT-AD1\tmp au lieu de \\THOT-AD1\c$\tmp

    Mais à présent ça me dit que le paramètre -Path de la commande Copy-Item n'est pas valide car le chemin renvoyé par la variable $Path (à savoir "\\THOT-AD1\tmp\System.evtx") n'existe pas ! pourtant ce chemin existe bien puisque la méthode .BackupEventlog($Path) l'a créée juste avant !



    • Modifié Nóla mercredi 10 juillet 2019 14:33
    mercredi 10 juillet 2019 12:42
  • tu dit :

    quand je lance le script rien ne ce passe, mais si je lance moi même la commande (en remplaçant les variables par les valeurs correspondante) la copie s'effectue 

    a tu fais comme je te l'ai dis un debug pour connaitre les valeur de tes variables ?

    si tu ne sais pas utilisé le debogage de ISE va voir chez Microsoft ou sur ce site 

    tu peut aussi faire un simple write-host comme tu le fais pour $server

    deuxième question : quand tu dis "je lance le script", tu le lance comment ? sur la même machine ? le même utilisateur ?   ok y a trois questions

    derniere question : a tu des messages d'erreurs ? il semble que oui peut nous les copier/coller ici 


    • Modifié 6ratgus mercredi 10 juillet 2019 17:07
    mercredi 10 juillet 2019 17:05
  • Oui le debug n'a révélé aucune anomalie de ce coté là, les variables renvoient bien les bonnes valeurs.

    Je pense que le problème vient du fait que le chemin renvoyé par $Path est un chemin local ! ( du genre "C:\tmp") il semblerait qu'il soit correctement interprété par la méthode .BackupEventlog comme un chemin pointant sur chaque machine à sauvegarder (et non pas un chemin sur la machine qui exécute le script) mais pas la commande Copy-Item.

    Partant de la je me suis orienté sur l'utilisation d'une commande intermédiaire "Invoke-Command" (avec ma commande de copie dans le BlockScript) ainsi que l'utilisation des sessions PS (il a bien fallu que je m'y mette du coup ^^).

    De là, nouveau problème => la commande me renvoi un jolie "Accès refusé" après recherche/vérification il semblerait que cela soit dû au fameux problème de "double saut" (même si je ne vois pas où il y a double saut puisque la copie se fait sur le PC qui exécute le script... )

    Nouveau problème = nouvelle solution : utilisation de l'authentification CredSSP, j’exécute donc les commandes

    Sur la station qui exécute le script :

    Enable-WSManCredSSP -Role Client -DelegateComputer "THOT-AD1, THOT-EXCH1"

    Sur les serveur à sauvegarder :

    Enable-WSManCredSSP -Role Server

    (Ou THOT-AD1 et THOT-EXCH1 sont les noms netbios de mes serveurs.)

    Mais voila ça ne fonctionne toujours qu'à moitié... sur le serveur THOT-EXCH1 c'est ok mais pas sur le THOT-AD1. Le serveur me renvoie l'erreur :

    New-PSSession : [THOT-AD1] Connecting to remote server THOT-AD1 failed with the following error message : Le client WinRM ne peut pas traiter la demande. Une stratégie d’ordinateur ne permet pas la 
    délégation des informations d’identification de l’utilisateur à l’ordinateur cible car ce dernier n’est pas approuvé. L’identité de l’ordinateur cible ne peut pas être vérifiée si vous configurez le 
    service WSMAN pour utiliser un certificat valide à l’aide de la commande suivante: winrm set winrm/config/service '@{CertificateThumbprint="<thumbprint>"}'  Sinon, vous pouvez rechercher dans 
    l’Observateur d’événements un événement qui spécifie que le SPN suivant n’a pas pu être créé: WSMAN/<computerFQDN>. Si vous trouvez cet événement, vous pouvez manuellement créer le SPN à l’aide de 
    setspn.exe.  Si le SPN existe, mais que CredSSP ne peut pas utiliser Kerberos pour valider l’identité de l’ordinateur cible et si vous souhaitez toujours autoriser la délégation des informations 
    d’identification de l’utilisateur à l’ordinateur cible, utilisez gpedit.msc et examinez la stratégie suivante: Configuration de l’ordinateur -> Modèles d’administration -> Système -> Délégation 
    d’informations d’identification -> Autoriser les nouvelles informations d’identification avec l’authentification du serveur NTLM uniquement.  Vérifiez qu’elle est activée et configurée avec un SPN 
    approprié pour l’ordinateur cible. Par exemple, pour le nom d’ordinateur cible «monserveur.domaine.com», le SPN peut être: WSMAN/monserveur.domaine.com ou WSMAN/*.domaine.com. Renouvelez la demande après 
    ces modifications. For more information, see the about_Remote_Troubleshooting Help topic.
    At Z:\LOG\Logs_Backup_v1.0a.ps1:331 char:18
    + ...        $s = New-PSSession -ComputerName $Server -Credential $Credenti ...
    +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException
        + FullyQualifiedErrorId : -2144108124,PSSessionOpenFailed

    Et la je suis bloqué...


    • Modifié Nóla vendredi 12 juillet 2019 12:04
    vendredi 12 juillet 2019 12:02
  • inutile de faire du credSSP si tu arrive a faire fonctionne ton code en mettent les valeurs en dure !!

    mais tu peut si tu veux regarde ce post sur le sujet 

    Oui le debug n'a révélé aucune anomalie de ce coté là, les variables renvoient bien les bonnes valeurs.

    bonne nouvelle donc la variable $path contient "\\THOT-AD1\c$\tmp\quelque chose.evtx" ?

    puisque ton code le construit ainsi :

    $Tmp = $TmpRaw.replace("<SERVEUR>", $Server)

    $Path = "$tmp\$Log.evtx"


    hors du dis :


    Je pense que le problème vient du fait que le chemin renvoyé par $Path est un chemin local ! ( du genre "C:\tmp") il semblerait qu'il soit correctement interprété par la méthode .BackupEventlog comme un chemin pointant sur chaque machine à sauvegarder (et non pas un chemin sur la machine qui exécute le script) mais pas la commande Copy-Item.


    si $path contient un lecteur local (du type c:\), c'est que ton code ne marche pas !! 

    mais tu a vérifier en debug ou avec un write-host que la variable est bonne. Donc ça doit marcher comme quand tu le fais à la main

    Copy-Item "\\THOT-AD\c$\tmp\*" -Destination "\\THOT-CLT\Backuplog\20191007_THOT-AD"

    si $path contient un lecteur local, c'est que ton code ne marche pas !! ? mais tu a vérifier en debug ou avec un write-host, la variable est bonne. Donc ça doit marcher comme quand tu le fais à la main

    j'insiste mais pour moi

    - soit la construction de ta variable $path ne fonctionne pas comme tu le veux 

    - soit tu n'utilise pas le script avec les mêmes paramètres (utilisateur, ordinateur, élévation admin) que quand tu faire la manip avec les valeurs en dure dans copy-item dans le script

    dernière info tu peut utilisé copy-item avec l'option fromsession ou tosession voir la doc

    qui permet la copie depuis un lecteur local d'un serveur distant vers un autre dossier local ou réseau


    • Modifié 6ratgus vendredi 12 juillet 2019 13:52
    vendredi 12 juillet 2019 13:40
  • Autant pour moi je n'ai pas précisé que j'avais testé une autre option avec la variable $Path, (au lieu de passer par le partage part défaut c$ je suis passé par un chemin local en "dur" de type C:\tmp que je manipulais via la commande Invoke-Commande) mais vu que cela n'a pas porté de fruit j'abandonne cette option et reprends le postulat de départ:

    La variable $Path fonctionne correctement et renvoie bien le résultat attendu à savoir par exemple "\\THOT-AD1\c$\tmp\System.evtx"

    Cette variable fonctionne correctement quand je l'utilise avec la méthode .BackupLog($Path) (Le fichier de log est correctement sauvegardé dans le dossier temporaire du serveur concerné)

    En revanche elle ne fonctionne pas que je tente de l’utiliser avec la commande Copy-Item ! J'obtiens à la place un jolie message d'erreur m'informant que "can not find path '\\THOT-AD1\c$\tmp\Application.evtx' because it does not exist"

    Du coup je tente de l'utiliser en passant par la commande Invoke-Commande, et là... ça fonctionne pour l'AD mais pas pour THOT-EXCH1 ! pour ce dernier j'obtiens le message d'erreur "Accès refusé"

    pour lancer le script je le fait depuis l'interface Powershell ISE (en mode admin), quand je tente d’exécuter la commande "manuellement" je le fait depuis l'invite Powershell ISE, juste sous mon script... tu penses que ça peut venir de là ?

    vendredi 12 juillet 2019 15:17
  • ok je vois plus clair maintenant

    pour lancer le script je le fait depuis l'interface Powershell ISE (en mode admin), quand je tente d’exécuter la commande "manuellement" je le fait depuis l'invite Powershell ISE, juste sous mon script... tu penses que ça peut venir de là ?

    non aucun problème par rapport a ces manip :)

    Cette variable fonctionne correctement quand je l'utilise avec la méthode .BackupLog($Path) (Le fichier de log est correctement sauvegardé dans le dossier temporaire du serveur concerné)

    avec BackupLog tu accède à distance au serveur THOT-AD1 via l'option -ComputerName du WMI. tu a donc un premier saut, ce qui explique pourquoi tu n'arrive pas a écrire directement sur le deuxième serveur car ça fais un deuxième saut (problème double hop)


    En revanche elle ne fonctionne pas que je tente de l’utiliser avec la commande Copy-Item ! J'obtiens à la place un jolie message d'erreur m'informant que "can not find path '\\THOT-AD1\c$\tmp\Application.evtx' because it does not exist"

    peut tu avec l'explorateur Windows avoir accès à ce dossier depuis la machine ou tu execute le script ??

    si non ton problème est la !!!

    source possible :

    - résolution DNS du nom du serveur THOT-AD sur ta machine,

    - blocage firewall,

    - limitation dans le partage de c$,

    - le dossier destination n'existe pas : celui avec la date et le nom du serveur (20191007_THOT_AD)  

    au passage des fois tu met AD1 des fois AD tout court

    si oui ,

    - je reviens encore sur le contenu de la variable $path

    - peut-etre faut t'il rajouter  un "\" a la fin de $BackupSubDir

    - il arrive parfois qu'un caractère invisible ce soit glissé dans la ligne du copy-item. solution il te retaper toute la ligne de code !!


    Du coup je tente de l'utiliser en passant par la commande Invoke-Commande, et là... ça fonctionne pour l'AD mais pas pour THOT-EXCH1 ! pour ce dernier j'obtiens le message d'erreur "Accès refusé"

    la c'est un problème d'autorisation d’accès ( le double saut ) !!! ton script tourne sur ta machine "A", tu te connecte au serveur "B" THOT-AD1 via invoke (premier saut) et depuis ce serveur AD tu essai d'accédé au serveur "C" THOT-EXCH1 pour le copy-item (deuxième saut)

    derniere idée avant le weekend :

    $ids = New-PSSession $server
    $Path = "c:\tmp\$Log.evtx"
    Copy-Item -FromSession $ids -Path $Path -Destination $BackupSubDir
    Remove-PSSession $ids
    

    pour info j'ai fait un test rapide de ton script sans soucis 

    • Modifié 6ratgus vendredi 12 juillet 2019 18:39
    vendredi 12 juillet 2019 18:09
  • Oui avec l'explorateur Windows j'y accède très bien, le contenu de cette variable ne peut tout simplement pas être faux puisque c'est exactement la même variable qui est utilisée juste au dessus pour le .BackupEventlog qui lui fonctionne très bien...

    Pour ce qui est de rajouter  un "\" a la fin de $BackupSubDir, je ne vois pas pourquoi puisque ce n'est pas cette variable qui est incriminée... (dans le doute j'ai testé mais sans résultat)

    A force de tripaturer mon script j'ai modifié le nom de certaines variables, pour plus de clarté je poste donc une version "simplifiée" du script...

    Param(
    $ErrorActionPreference = 'stop',
    $ConfFile = "$LocalPath\Configuration.ini",
    $TempRaw = "\\<SERVEUR>\c$\Temp"
    )
    
    Function Import-Conf
    {
        $ItemFileConf = Get-Item -Path $ConfFile
        
        #Remplissage de la table de hash avec les éléments du fichier .ini
        $ConfTable = @{} 
        Switch -Regex -File $ItemFileConf
            {...}
           
        #Déclaration des nouvelles variables
        $Script:ListLogs = $ConfTable.PARAMETRES["Logs"]
        $Script:BackupDirPath = $ConfTable.PARAMETRES["Dossier_Backup"]
        $Script:BackupDirName =$ConfTable.PARAMETRES["Dossier_Backup"].split("\")[-1]
        $Script:BackupPCName = $ConfTable.PARAMETRES["Dossier_Backup"].split("\")[2] 
        $Script:ServerList = $ConfTable.SERVEURS.Keys       
        Ctrl-Server
    } #End Import-Conf
    
    Function Ctrl-Server
    {...} #End Ctrl-Server
    
    Function Ctrl-BackupDir
    {...} #End Ctrl-BackupDir
    
    Function Ctrl-TmpDir
    {...} #End Ctrl-TmpDir
    
    Function Backup-EventLogs
    {
        Write-Host "`nDébut de la sauvegarde des logs.`n" -ForegroundColor Green
        $Date = Get-Date -Format "yyyyMMdd"
        $Logs = $ListLogs.Split(",")
    
        Foreach($Server in $ServerList)
            {
                $Temp = $TempRaw.replace("<SERVEUR>", $Server)
                $BackupSubDir = $BackupDirPath+"\"+$Date+"_"+$Server
                Write-Host "|| $Server ||`n" -ForegroundColor Gray
                
                #Controle du sous-dossier de sauvegarde des log (dossier du jour du type "20190703_THOT-AD1"]
                If(Test-Path $BackupSubDir)
                    {...} 
    
                Foreach($Log in $Logs)
                    {
                        Try
                            {
                                $LogBackupTempPath = "$Temp\$Log.evtx"
                                $BackupLog = Get-WmiObject -Class Win32_NTEventlogFile -ComputerName $Server | Where-Object LogfileName -eq $Log
                                $BackupLog.BackupEventlog($LogBackupTempPath) | Out-Null
                                $LogBackupTempPath
                                Copy-Item -Path "\\THOT-AD1\c$\Temp\Application.evtx" -Destination $BackupSubDir -Force
                                #Invoke-Command -ComputerName $Server -ScriptBlock{param($LogBackupTempPath, $BackupSubDir)Copy-Item -Path $LogBackupTempPath -Destination $BackupSubDir -Force} -ArgumentList $LogBackupTempPath, $BackupSubDir
                                Write-Host "    $Log.evtx... OK"
                            }
                        Catch
                            {...}
                    } #End Foreach Logs
            } #End Foreach Serveurs
    } #End Backup-EventLogs
    
    $LocalPath = Split-Path -parent $MyInvocation.MyCommand.Definition
    
    Clear-Host
    Ctrl-ConfFile
    

    Pour le double saut ce que je ne comprends pas c'est pourquoi je passerai du Serveur B au Serveur C ?

    Mon script s’exécute sur la machine A, se connecte sur B (THOT-AD1) avec Invoke d'où il lance la copie des log à destination de A ! Ça compte vraiment pour un double saut ? Même si la commande est à destination de la machine d'origine ?


    samedi 13 juillet 2019 05:56

  • Mon script s’exécute sur la machine A, se connecte sur B (THOT-AD1) avec Invoke d'où il lance la copie des log à destination de A ! Ça compte vraiment pour un double saut ? Même si la commande est à destination de la machine d'origine ?


    c'est un double même si la machine C est la A !! dommage

    a tu essayer la solution suivante :

    $ids = New-PSSession $server
    $Path = "c:\tmp\$Log.evtx"
    Copy-Item -FromSession $ids -Path $Path -Destination $BackupSubDir
    Remove-PSSession $ids

    • Marqué comme réponse Nóla lundi 15 juillet 2019 07:00
    samedi 13 juillet 2019 15:37
  • Cette fois-ci c'est la bonne ! ça fonctionne ! J'ai juste dû changer le chemin du dossier temporaire pour un chemin local (C:\Temp) mais maintenant tout fonctionne parfaitement ! merci de ton aide 6ratgus :-)
    lundi 15 juillet 2019 07:02